/* ---- This file is part of SECONDO. Copyright (C) 2013, University in Hagen, Faculty of Mathematics and Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}] //[TOC] [\tableofcontents] //[ue] [\"u] //[ae] [\"a] //[oe] [\"o] \setcounter{tocdepth}{4} [1] Implementation of the ~MovingRegion3Algebra~ May 2012, initial version created by Stefanie Renner for master thesis with Prof. Dr. G[ue]ting, Fachbereich Informatik, Fernuniversit[ae]t Hagen. September 2013, revised and enlarged version of the prior MovingRegion2Algebra by Oliver Feuer for bachelor thesis. The following things have been changed or added: * the algebra is based on the Region2Algebra with a precise region2-object * the scalefactor is an integer to base 10 and can be set by ~setscalefactor~ * the integer parts of the objects are save according an integer overflow * the precise parts are stored more compactly in a DbArray of unsigned int * the grid of the time is now based on the instant-time * the instant type iregion2 is now available * the operators atinstant, initial and final are updated * operators ~inside~ and ~intersection~ for MPoints are added * operator ~traversed~ is added * additional operators for scaling, transforming and timeshift * all data types can be schown by the HoeseViewer [TOC] 1 Introduction The ~MovingRegion3Algebra~ 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. The class definitions of ~MSegmentData2~, ~PreciseMSegmentData~, ~PreciseInterval~, ~TrapeziumSegmentIntersection2~, ~IRegion2~, ~URegionEmb2~, ~URegion2~ and ~MRegion2~, which are implemented in ~MovingRegion3Algebra.cpp~, have been moved to the header file ~MovingRegion3Algebra.h~ to facilitate development work on top of the ~MovingRegion3Algebra~ without modifying the ~MovingRegion3Algebra~ itself. This file contains detailed descriptions for the usage of the methods of these classes too. 1 Defines and includes */ #include "MovingRegion3Algebra.h" #include "Refinement2.h" using namespace std; using namespace datetime; namespace temporalalgebra{ /* 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; /* 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( double a, double b, double c, double d, 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; } 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 Reg2GridPoint, GridPointSegment, Reg2ProvisionalPoint, 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(Reg2ProvisionalPoint point1, Reg2ProvisionalPoint point2) { return (maybeEqual(point1.x, point2.x, point1.xErr, point2.xErr) && maybeEqual(point1.y, point2.y, point1.yErr, point2.yErr)); } static bool maybeEqual(Reg2GridPoint point1, Reg2GridPoint 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))); } 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))); } 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. */ 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; } 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; } 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; } 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 double value inValue and returns its representation as mpq\_class. */ 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()~ Function is moved to Region2Tools.h of the Region2-Algebra 1.1.1.1 Function ~textTypeToGmpType()~ Function is moved to Region2Tools.h of the Region2-Algebra */ /* 1.1.1.1 ~instant2MPQ~ This method converts instant type i to mpq\_class without lost of precision */ static mpq_class instant2MPQ( const Instant i ) { mpq_class res = mpq_class(0); int days = (int)i.ToDouble(); const int rest = i.GetAllMilliSeconds(); const int milliseconds = 86400000; res = days + mpq_class(rest, milliseconds); res.canonicalize(); return res; } /* 1.1.1.1 ~precTimeToInstant~ This method converts a precise mpq\_class time value to an instant part with full milliseconds and a resting value of type mpq\_class without lost of precision */ static void precTimeToInstant(const mpq_class prectime, Instant& timeValue, mpq_class& restValue) { int days = (int)prectime.get_d(); const int milliseconds = 86400000; mpq_class millipart = (prectime - days) * milliseconds; int millis = (int)millipart.get_d(); timeValue = Instant(days, millis, datetime::instanttype); restValue = (millipart - millis) / milliseconds; restValue.canonicalize(); } /* 1.1 Geometrical helper types 1.1.1 Class ~Reg2GridPoint~ This class is moved to Reg2Points.h of the Region2-Algebra 1.1.1 Class ~Reg2ProvisionalPoint~ This class is moved to Reg2Points.h of the Region2-Algebra 1.1.1 Class ~Reg2PrecisePoint~ This class is moved to Reg2Points.h of the Region2-Algebra 1.1.1 Class ~GridPointSegment~ 1.1.1.1 Constructors */ GridPointSegment::GridPointSegment(Reg2GridPoint point1, Reg2GridPoint point2) : point1 (point1), point2 (point2), isBasic (point1.isBasic && point2.isBasic) {} GridPointSegment::GridPointSegment(Reg2GridPoint point1, Reg2GridPoint 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(Reg2ProvisionalPoint point1, Reg2ProvisionalPoint 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(Reg2PrecisePoint point1, Reg2PrecisePoint 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; } } 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 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] = {{ (double) segment1.point2.x-segment1.point1.x, (double) segment2.point1.x-segment2.point2.x }, { (double) segment1.point2.y-segment1.point1.y, (double) segment2.point1.y-segment2.point2.y }, { (double)dt, (double)-dt}}; double B[3] = { (double)segment2.point1.x-segment1.point1.x, (double)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 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] = {{ (double)segment1.point2.x-segment1.point1.x, (double)segment2.point1.x-segment2.point2.x }, { (double)segment1.point2.y-segment1.point1.y, (double)segment2.point1.y-segment2.point2.y }, { (double)dt, (double)-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 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; } } 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 (final)" << endl; return true; } /* 1.1.1 Intersections between two trapeziums 1.1.1.1 Function ~trapeziumsMayIntersect()~ 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 < 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(); Reg2ProvisionalPoint point1(P[0], P[1], Perr[0], Perr[1]); Reg2ProvisionalPoint 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 (1)" << 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 (2)" << 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(); Reg2PrecisePoint point1(P[0], P[1]); Reg2PrecisePoint 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 (3)" << 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, Reg2GridPoint 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. */ Reg2ProvisionalPoint point1(trapezium.segment1.point1.x, trapezium.segment1.point1.y, 1, 1); Reg2ProvisionalPoint 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, Reg2PrecisePoint 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. */ Reg2PrecisePoint point1(trapezium.segment1.point1.x, trapezium.segment1.point1.y); Reg2PrecisePoint 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()~ */ bool maybeLeftOrAbove(Reg2GridPoint 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()~ */ bool preciseLeftOrAbove(Reg2PrecisePoint 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 precTimeInterval iv, UPoint& rUp) { if (MR2_DEBUG) cerr << "restrictUPointToInterval() called" << endl; double ti = 0; double tf = 0; Instant start(datetime::instanttype); mpq_class reststart(0); precTimeToInstant(iv.start, start, reststart); Instant end(datetime::instanttype); mpq_class restend(0); precTimeToInstant(iv.end, end, restend); if (cmp(reststart, 0) > 0) start += Instant(0, 1, datetime::durationtype); if (up.timeInterval.end != up.timeInterval.start) { ti = (start - up.timeInterval.start) / (up.timeInterval.end - up.timeInterval.start); tf = (end - up.timeInterval.start) / (up.timeInterval.end - up.timeInterval.start); } double p1x = up.p0.GetX() + ( up.p1.GetX() - up.p0.GetX() )*ti; double p1y = up.p0.GetY() + ( up.p1.GetY() - up.p0.GetY() )*ti; double p2x = up.p0.GetX() + ( up.p1.GetX() - up.p0.GetX() )*tf; double p2y = up.p0.GetY() + ( up.p1.GetY() - up.p0.GetY() )*tf; rUp = UPoint(Interval(start, end, iv.lc, iv.rc), p1x, p1y, p2x, p2y); } /* 1 Supporting classes Supporting classes are those, which are not registered as SECONDO datatypes but are used to implement the SECONDO datatypes ~iregion2~, ~uregion2~ and ~mregion2~. 1.1 Class ~MSegmentData2~ This class is used to represent the segments, which are used to represent region units in section. 1.1.1 Class definition The class definition has been moved to ~MovingRegion3Algebra.h~. 1.1.1 Constructor for a basic segment */ 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() #1 " << "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." <<"("<* 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. */ mpq_class pisx = mpq_class(isx) + preciseSegment. GetInitialStartX(preciseCoordinates); pisx.canonicalize(); mpq_class pisy = mpq_class(isy) + preciseSegment. GetInitialStartY(preciseCoordinates); pisy.canonicalize(); mpq_class piex = mpq_class(iex) + preciseSegment. GetInitialEndX(preciseCoordinates); piex.canonicalize(); mpq_class piey = mpq_class(iey) + preciseSegment. GetInitialEndY(preciseCoordinates); piey.canonicalize(); mpq_class pfsx = mpq_class(fsx) + preciseSegment. GetFinalStartX(preciseCoordinates); pfsx.canonicalize(); mpq_class pfsy = mpq_class(fsy) + preciseSegment. GetFinalStartY(preciseCoordinates); pfsy.canonicalize(); mpq_class pfex = mpq_class(fex) + preciseSegment. GetFinalEndX(preciseCoordinates); pfex.canonicalize(); mpq_class pfey = mpq_class(fey) + preciseSegment. GetFinalEndY(preciseCoordinates); pfey.canonicalize(); pointInitial = cmp(pisx, piex) == 0 && cmp(pisy, piey) == 0; pointFinal = cmp(pfsx, pfex) == 0 && cmp(pfsy, pfey) == 0; /* 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. */ 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 collinear. */ if (MR2_DEBUG) cerr << "MSegmentData2::MSegmentData2() " << "final reduced" << endl; collinear = true; } else if ((cmp(pisx, piex) == 0) && (cmp(pfsx, pfex) == 0)) { /* Both segments are vertical. Check if both segments have the same orientation. */ if (MR2_DEBUG) cerr << "MSegmentData2::MSegmentData2() " << "both vertical" << endl; collinear = ((cmp(pisy, piey) <= 0) && (cmp(pfsy, pfey) <= 0)) || ((cmp(pisy, piey) >= 0) && (cmp(pfsy, pfey) >= 0)); /* Only initial or final segment is vertical but not both. */ } else if ((cmp(pisx, piex) == 0) || (cmp(pfsx, pfex) == 0)) { if (MR2_DEBUG) cerr << "MSegmentData2::MSegmentData2() " << "only one vertical! " << endl; 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 i 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! */ if (MR2_DEBUG) cerr << "MSegmentData2::MSegmentData2() " << "none vertical" << endl; mpq_class IYIX = (piey - pisy)/(piex - pisx); IYIX.canonicalize(); mpq_class FYFX = (pfey - pfsy)/(pfex - pfsx); FYFX.canonicalize(); mpq_class IYFX = (piey - pisy)*(pfex - pfsx); IYFX.canonicalize(); mpq_class FYIX = (pfey - pfsy)*(piex - pisx); FYIX.canonicalize(); collinear = (cmp(IYIX, FYFX) == 0) || (cmp(IYFX, FYIX) == 0); if (MR2_DEBUG) { cerr << "MSegmentData2::MSegmentData2() pisx=" << pisx << " pisy=" << pisy << endl << " piex=" << piex << " piey=" << piey << endl << " pfsx=" << pfsx << " pfsy=" << pfsy << endl << " pfex=" << pfex << " pfey=" << pfey << endl; cerr << "parameters for " << "segment orientation comparison:" << endl; cerr << "MSegmentData2::MSegmentData2() (iey-isy)/(iex-isx)=" << IYIX << endl; cerr << "MSegmentData2::MSegmentData2() (fey-fsy)/(fex-fsx)=" << FYFX << endl; cerr << "MSegmentData2::MSegmentData2() (iey-isy)*(fex-fsx)=" << IYFX << endl; cerr << "MSegmentData2::MSegmentData2() (fey-fsy)*(iex-isx)=" << FYIX << endl; cerr << "MSegmentData2::MSegmentData2() collinear=" << collinear << endl; cerr << "1. and 2. or 3. and 4. should be equal." << endl; } } //Check if collinear if (!collinear) { throw invalid_argument( "initial and final segment not collinear (2)"); } } //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), pointInitial(segmentPointer->pointInitial), pointFinal(segmentPointer->pointFinal) { 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 ~MovingRegion3Algebra.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, int isxdPos, int isydPos, int iexdPos, int ieydPos, int fsxdPos, int fsydPos, int fexdPos, int feydPos, int isxdNum, int isydNum, int iexdNum, int ieydNum, int fsxdNum, int fsydNum, int fexdNum, int feydNum) : 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), isxdStartPos(isxdPos), isydStartPos(isydPos), iexdStartPos(iexdPos), ieydStartPos(ieydPos), fsxdStartPos(fsxdPos), fsydStartPos(fsydPos), fexdStartPos(fexdPos), feydStartPos(feydPos), isxdNumOfChars(isxdNum), isydNumOfChars(isydNum), iexdNumOfChars(iexdNum), ieydNumOfChars(ieydNum), fsxdNumOfChars(fsxdNum), fsydNumOfChars(fsydNum), fexdNumOfChars(fexdNum), feydNumOfChars(feydNum) {} 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), isxdStartPos(startPos), isydStartPos(startPos), iexdStartPos(startPos), ieydStartPos(startPos), fsxdStartPos(startPos), fsydStartPos(startPos), fexdStartPos(startPos), feydStartPos(startPos), isxdNumOfChars(0), isydNumOfChars(0), iexdNumOfChars(0), ieydNumOfChars(0), fsxdNumOfChars(0), fsydNumOfChars(0), fexdNumOfChars(0), feydNumOfChars(0) {} /* 1.1.1 Write access methods. All these methods take the argument of type mpq-class, convert it to two values of type mpz\_class representing the numerator and the denominator of the mpq-value. Each value of type mpz-class is divided into several unsigned integer numbers and stored in the given DbArray. The private attributes representing the array indices to restore the coordinates are of course also updated. Function SetValueX is moved to Region2Tools.h of the Region2-Algebra */ void PreciseMSegmentData::SetInitialStartX (mpq_class x, DbArray* preciseCoordinates) { if (MR2_DEBUG) cerr << "PreciseMSegmentData::SetInitialStartX() " << "called with isx = " << x << ", starting at array position " << isxStartPos << ", array address is " << preciseCoordinates << endl; if (cmp(x.get_num(), 0) == 0) return; SetValueX(x.get_num(), preciseCoordinates,isxStartPos,isxNumOfChars); SetValueX(x.get_den(), preciseCoordinates,isxdStartPos,isxdNumOfChars); } void PreciseMSegmentData::SetInitialStartY (mpq_class x, DbArray* preciseCoordinates) { if (MR2_DEBUG) cerr << "PreciseMSegmentData::SetInitialStartY() called" << endl; if (cmp(x.get_num(), 0) == 0) return; SetValueX(x.get_num(), preciseCoordinates,isyStartPos,isyNumOfChars); SetValueX(x.get_den(), preciseCoordinates,isydStartPos,isydNumOfChars); } void PreciseMSegmentData::SetInitialEndX (mpq_class x, DbArray* preciseCoordinates) { if (cmp(x.get_num(), 0) == 0) return; SetValueX(x.get_num(), preciseCoordinates,iexStartPos,iexNumOfChars); SetValueX(x.get_den(), preciseCoordinates,iexdStartPos,iexdNumOfChars); } void PreciseMSegmentData::SetInitialEndY (mpq_class x, DbArray* preciseCoordinates) { if (cmp(x.get_num(), 0) == 0) return; SetValueX(x.get_num(), preciseCoordinates,ieyStartPos,ieyNumOfChars); SetValueX(x.get_den(), preciseCoordinates,ieydStartPos,ieydNumOfChars); } void PreciseMSegmentData::SetFinalStartX (mpq_class x, DbArray* preciseCoordinates) { if (cmp(x.get_num(), 0) == 0) return; SetValueX(x.get_num(), preciseCoordinates,fsxStartPos,fsxNumOfChars); SetValueX(x.get_den(), preciseCoordinates,fsxdStartPos,fsxdNumOfChars); } void PreciseMSegmentData::SetFinalStartY (mpq_class x, DbArray* preciseCoordinates) { if (cmp(x.get_num(), 0) == 0) return; SetValueX(x.get_num(), preciseCoordinates,fsyStartPos,fsyNumOfChars); SetValueX(x.get_den(), preciseCoordinates,fsydStartPos,fsydNumOfChars); } void PreciseMSegmentData::SetFinalEndX (mpq_class x, DbArray* preciseCoordinates) { if (cmp(x.get_num(), 0) == 0) return; SetValueX(x.get_num(), preciseCoordinates,fexStartPos,fexNumOfChars); SetValueX(x.get_den(), preciseCoordinates,fexdStartPos,fexdNumOfChars); } void PreciseMSegmentData::SetFinalEndY (mpq_class x, DbArray* preciseCoordinates) { if (cmp(x.get_num(), 0) == 0) return; SetValueX(x.get_num(), preciseCoordinates,feyStartPos,feyNumOfChars); SetValueX(x.get_den(), preciseCoordinates,feydStartPos,feydNumOfChars); } /* 1.1.1 Read access methods All these methods fetch the unsigned integer parts of the numerator and the denominator 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. Function GetValueX is moved to Region2Tools.h of the Region2-Algebra */ mpq_class PreciseMSegmentData::GetInitialStartX(const DbArray* preciseCoordinates) const { if (MR2_DEBUG) cerr << "PreciseMSegmentData::GetInitialStartX()," << " isxNumOfChars: " << isxNumOfChars << ", isxStartPos: " << isxStartPos << ", array size: " << preciseCoordinates->Size() << endl; if (isxNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(isxStartPos, isxNumOfChars, preciseCoordinates); mpz_class den = GetValueX(isxdStartPos, isxdNumOfChars, preciseCoordinates); return mpq_class(num, den); } mpq_class PreciseMSegmentData::GetInitialStartY(const DbArray* preciseCoordinates) const { if (isyNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(isyStartPos, isyNumOfChars, preciseCoordinates); mpz_class den = GetValueX(isydStartPos, isydNumOfChars, preciseCoordinates); return mpq_class(num, den); } mpq_class PreciseMSegmentData::GetInitialEndX(const DbArray* preciseCoordinates) const { if (iexNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(iexStartPos, iexNumOfChars, preciseCoordinates); mpz_class den = GetValueX(iexdStartPos, iexdNumOfChars, preciseCoordinates); return mpq_class(num, den); } mpq_class PreciseMSegmentData::GetInitialEndY(const DbArray* preciseCoordinates) const { if (ieyNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(ieyStartPos, ieyNumOfChars, preciseCoordinates); mpz_class den = GetValueX(ieydStartPos, ieydNumOfChars, preciseCoordinates); return mpq_class(num, den); } mpq_class PreciseMSegmentData::GetFinalStartX(const DbArray* preciseCoordinates) const { if (fsxNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(fsxStartPos, fsxNumOfChars, preciseCoordinates); mpz_class den = GetValueX(fsxdStartPos, fsxdNumOfChars, preciseCoordinates); return mpq_class(num, den); } mpq_class PreciseMSegmentData::GetFinalStartY(const DbArray* preciseCoordinates) const { if (fsyNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(fsyStartPos, fsyNumOfChars, preciseCoordinates); mpz_class den = GetValueX(fsydStartPos, fsydNumOfChars, preciseCoordinates); return mpq_class(num, den); } mpq_class PreciseMSegmentData::GetFinalEndX(const DbArray* preciseCoordinates) const { if (fexNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(fexStartPos, fexNumOfChars, preciseCoordinates); mpz_class den = GetValueX(fexdStartPos, fexdNumOfChars, preciseCoordinates); return mpq_class(num, den); } mpq_class PreciseMSegmentData::GetFinalEndY(const DbArray* preciseCoordinates) const { if (feyNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(feyStartPos, feyNumOfChars, preciseCoordinates); mpz_class den = GetValueX(feydStartPos, feydNumOfChars, preciseCoordinates); return mpq_class(num, den); } /* 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 ~MovingRegion3Algebra.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, int startdPos, int enddPos, int startdNum, int enddNum) : startStartPos(startPos), endStartPos(endPos), startNumOfChars(startNum), endNumOfChars(endNum), startdStartPos(startdPos), enddStartPos(enddPos), startdNumOfChars(startdNum), enddNumOfChars(enddNum) {} PreciseInterval::PreciseInterval(int pos) : startStartPos(pos), endStartPos(pos), startNumOfChars(0), endNumOfChars(0), startdStartPos(pos), enddStartPos(pos), startdNumOfChars(0), enddNumOfChars(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 unsigned integer arrays to retrieve the objects, and when object values are updated, the indices are updated as well. */ mpq_class PreciseInterval::GetPreciseInitialInstant ( const DbArray* preciseInstants) { if (startNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(startStartPos, startNumOfChars, preciseInstants); mpz_class den = GetValueX(startdStartPos, startdNumOfChars, preciseInstants); return mpq_class(num, den); } mpq_class PreciseInterval::GetPreciseFinalInstant ( const DbArray* preciseInstants) { if (endNumOfChars == 0) return mpq_class(0); mpz_class num = GetValueX(endStartPos, endNumOfChars, preciseInstants); mpz_class den = GetValueX(enddStartPos, enddNumOfChars, preciseInstants); return mpq_class(num, den); } void PreciseInterval::SetPreciseInitialInstant ( mpq_class initial, DbArray* preciseInstants) { if (cmp(initial.get_num(), 0) == 0) return; SetValueX(initial.get_num(), preciseInstants, startStartPos, startNumOfChars); SetValueX(initial.get_den(), preciseInstants, startdStartPos, startdNumOfChars); } void PreciseInterval::SetPreciseFinalInstant ( mpq_class final, DbArray* preciseInstants) { if (cmp(final.get_num(), 0) == 0) return; SetValueX(final.get_num(), preciseInstants, endStartPos, endNumOfChars); SetValueX(final.get_den(), preciseInstants, enddStartPos, enddNumOfChars); } /* 1 Data type ~iregion2~ 1.1 Class ~IRegion2~ 1.1.1 Class definition The class definition has been moved to ~MovingRegion3Algebra.h~. 1.1.1 Constructors */ IRegion2::IRegion2(bool dummy): Intime(0) { if (MR2_DEBUG) cerr << "IRegion2::IRegion2() #1 called" << endl; value.SetEmpty(); value.SetDefined(true); SetDefined(true); } IRegion2::IRegion2(const IRegion2& ir) : Intime(ir.instant, ir.value) { if (MR2_DEBUG) cerr << "IRegion2::IRegion2() #2 called" << endl; if(!ir.IsDefined()){ SetDefined(false); return; } } IRegion2::IRegion2(const Instant& instant, const Region2& region2): Intime(instant,region2){} /* 1.1.1 Methods for algebra integration 1.1.1.1 Method ~Clone()~ clone method: */ IRegion2* IRegion2::Clone(void) const { if (MR2_DEBUG) cerr << "IRegion2::Clone() called" << endl; return new IRegion2(*this); } /* 1.1.1.1 ~DBArray~ access access to the DbArrays */ int IRegion2::NumOfFLOBs(void) const { if (MR2_DEBUG) cerr << "IRegion2::NumOfFLOBs() called" << endl; return value.NumOfFLOBs(); } Flob* IRegion2::GetFLOB(const int i) { if (MR2_DEBUG) cerr << "IRegion2::GetFLOB() called" << endl; return value.GetFLOB(i); } /* 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\" ((((0 (1 3 ('0' '1/2'))(2 5 ('0' '1/2'))" "(3 6 ('0' '1/2'))(4 6 ('0' '1/2'))(4 5 ('0' '1/2'))(5 4 " "('0' '1/2'))(5 2 ('0' '1/2'))(4 1 ('0' '1/2'))(3 1 ('0' " "'1/2')))((2 3 ())(2 4 ())(3 4 ())(3 3 ()))))))"); 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("( )"), example)); } /* 1.1.1 Function ~InIRegion2()~ */ Word InIRegion2( const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct ){ if(listutils::isSymbolUndefined( instance ) ){ IRegion2* res = new IRegion2(false); res->SetDefined(false); correct = true; return SetWord(res); } if(!nl->HasLength(instance,2)){ correct = false; return SetWord((void*)0); } ListExpr inst = nl->First(instance); ListExpr reg = nl->Second(instance); Instant* instant = (Instant *)InInstant( nl->TheEmptyList(), inst, errorPos, errorInfo, correct ).addr; if(!correct){ if(instant){ delete instant; } return SetWord((void*)0); } Region2* region2 = (Region2*)InRegion2( nl->TheEmptyList(), reg, errorPos, errorInfo, correct).addr; if(!correct){ if(region2){ delete region2; } delete instant; return SetWord((void*)0); } IRegion2* res = new IRegion2(*instant, *region2); delete instant; delete region2; correct = true; return SetWord(res); } /* 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 Function ~DeleteIRegion2()~ */ void DeleteIRegion2(const ListExpr typeInfo, Word &w){ IRegion2* ir = (IRegion2*) w.addr; delete ir; w.addr=0; } /* 1.1.1 Function ~OpenIRegion2()~ */ bool OpenIRegion2(SmiRecord& rec, size_t& offset, const ListExpr typeInfo, Word& w) { if (MR2_DEBUG) cerr << "OpenIRegion2() called" << endl; w = SetWord(Attribute::Open(rec, offset, typeInfo)); return true; } /* 1.1.1 Function ~SaveIRegion2()~ */ static bool SaveIRegion2(SmiRecord& rec, size_t& offset, const ListExpr typeInfo, Word& w) { if (MR2_DEBUG) cerr << "SaveIRegion2() called" << endl; IRegion2* ir = static_cast (w.addr); Attribute::Save(rec, offset, typeInfo, ir); return true; } /* 1.1.1 Function ~CloseIRegion2()~ */ void CloseIRegion2(const ListExpr typeInfo, Word &w){ IRegion2* ir = (IRegion2*) w.addr; delete ir; w.addr=0; } /* 1.1.1 Function ~CloneIRegion2()~ */ Word CloneIRegion2( const ListExpr typeInfo, const Word& w ) { return SetWord( new IRegion2( * ((IRegion2*)w.addr))); } /* 1.1.1 Function ~CastIRegion2()~ */ void* CastIRegion2( void* addr ) { return (new (addr) IRegion2); } /* 1.1.1 Function ~SizeOfIRegion2()~ */ int SizeOfIRegion2() { return sizeof(IRegion2); } /* 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 Type constructor ~intimeregion2~ */ static TypeConstructor intimeregion2( IRegion2::BasicType(), IRegion2Property, OutIntime, InIRegion2, 0, 0, // SaveToList, RestoreFromList CreateIRegion2, DeleteIRegion2, OpenIRegion2, SaveIRegion2, CloseIRegion2, CloneIRegion2, CastIRegion2, SizeOfIRegion2, CheckIRegion2 ); /* 1 Class ~URegionEmb2~ 1.1 Class definition The class definition has been moved to ~MovingRegion3Algebra.h~. 1.1 Constructors */ URegionEmb2::URegionEmb2( const bool Defined ) : segmentsStartPos(0), segmentsNum(0), bbox(false), minIntx(0), minInty(0), maxIntx(0), maxInty(0), minPrecx(0), minPrecy(0), maxPrecx(0), maxPrecy(0) { if (MR2_DEBUG) cerr << "URegionEmb2::URegionEmb2(bool) called" << endl; } URegionEmb2::URegionEmb2(const Interval& tiv, const PreciseInterval& piv, unsigned int pos) : segmentsStartPos(pos), segmentsNum(0), bbox(false), timeInterval(tiv), pInterval(piv), minIntx(0), minInty(0), maxIntx(0), maxInty(0), minPrecx(0), minPrecy(0), maxPrecx(0), maxPrecy(0) { if (MR2_DEBUG) cerr << "URegionEmb2::URegionEmb2(tiv, piv, pos) called" << endl; } URegionEmb2::URegionEmb2(DbArray* segments, DbArray* preciseSegments, DbArray* preciseCoordinates, DbArray* preciseInstants, const Interval& tiv, PreciseInterval& piv, const URegionEmb& origUremb, const DbArray* origSegments, unsigned int pos, 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); } minIntx = 0; minInty = 0; maxIntx = 0; maxInty = 0; minPrecx = mpq_class(0); minPrecy = mpq_class(0); maxPrecx = mpq_class(0); maxPrecy = mpq_class(0); mpz_t sFactor; mpz_init(sFactor); mpq_class sFac(0); uint sfactor; if (scaleFactor < 0) { sfactor = -scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(1), mpz_class(sFactor)); } else { sfactor = scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(sFactor), mpz_class(1)); } sFac.canonicalize(); mpz_clear(sFactor); //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 << " with orig coordinates:" << endl; if (MR2_DEBUG) cerr << " - isx: " << segment.GetInitialStartX() << " - isy: " << segment.GetInitialStartY() << " - iex: " << segment.GetInitialEndX() << " - iey: " << segment.GetInitialEndY() << " - fsx: " << segment.GetFinalStartX() << " - fsy: " << segment.GetFinalStartY() << " - fex: " << segment.GetFinalEndX() << " - fey: " << segment.GetFinalEndY() << endl; //calculate new coordinates... mpq_class pisx(segment.GetInitialStartX()); mpq_class pisy(segment.GetInitialStartY()); if ( overflowAsInt(pisx, pisy, scaleFactor) ) { segmentsNum = 0; return; } mpq_class piex(segment.GetInitialEndX()); mpq_class piey(segment.GetInitialEndY()); if ( overflowAsInt(piex, piey, scaleFactor) ) { segmentsNum = 0; return; } mpq_class pfsx(segment.GetFinalStartX()); mpq_class pfsy(segment.GetFinalStartY()); if ( overflowAsInt(pfsx, pfsy, scaleFactor) ) { segmentsNum = 0; return; } mpq_class pfex(segment.GetFinalEndX()); mpq_class pfey(segment.GetFinalEndY()); if ( overflowAsInt(pfex, pfey, scaleFactor) ) { segmentsNum = 0; return; } if (cmp(pisx, maxPrecx) > 0) maxPrecx = pisx; if (cmp(pisy, maxPrecy) > 0) maxPrecy = pisy; if (cmp(piex, maxPrecx) > 0) maxPrecx = piex; if (cmp(piey, maxPrecy) > 0) maxPrecy = piey; if (cmp(pfsx, maxPrecx) > 0) maxPrecx = pfsx; if (cmp(pfsy, maxPrecy) > 0) maxPrecy = pfsy; if (cmp(pfex, maxPrecx) > 0) maxPrecx = pfex; if (cmp(pfey, maxPrecy) > 0) maxPrecy = pfey; if (cmp(pisx, minPrecx) < 0) minPrecx = pisx; if (cmp(pisy, minPrecy) < 0) minPrecy = pisy; if (cmp(piex, minPrecx) < 0) minPrecx = piex; if (cmp(piey, minPrecy) < 0) minPrecy = piey; if (cmp(pfsx, minPrecx) < 0) minPrecx = pfsx; if (cmp(pfsy, minPrecy) < 0) minPrecy = pfsy; if (cmp(pfex, minPrecx) < 0) minPrecx = pfex; if (cmp(pfey, minPrecy) < 0) minPrecy = pfey; pisx = pisx * sFac; pisy = pisy * sFac; piex = piex * sFac; piey = piey * sFac; pfsx = pfsx * sFac; pfsy = pfsy * sFac; pfex = pfex * sFac; pfey = pfey * sFac; pisx.canonicalize(); pisy.canonicalize(); piex.canonicalize(); piey.canonicalize(); pfsx.canonicalize(); pfsy.canonicalize(); pfex.canonicalize(); pfey.canonicalize(); int isx = (int)floor(pisx.get_d()); int isy = (int)floor(pisy.get_d()); int iex = (int)floor(piex.get_d()); int iey = (int)floor(piey.get_d()); int fsx = (int)floor(pfsx.get_d()); int fsy = (int)floor(pfsy.get_d()); int fex = (int)floor(pfex.get_d()); int fey = (int)floor(pfey.get_d()); if (isx > maxIntx) maxIntx = isx; if (isy > maxInty) maxInty = isy; if (iex > maxIntx) maxIntx = iex; if (iey > maxInty) maxInty = iey; if (fsx > maxIntx) maxIntx = fsx; if (fsy > maxInty) maxInty = fsy; if (fex > maxIntx) maxIntx = fex; if (fey > maxInty) maxInty = fey; if (isx < minIntx) minIntx = isx; if (isy < minInty) minInty = isy; if (iex < minIntx) minIntx = iex; if (iey < minInty) minInty = iey; if (fsx < minIntx) minIntx = fsx; if (fsy < minInty) minInty = fsy; if (fex < minIntx) minIntx = fex; if (fey < minInty) minInty = fey; pisx = pisx - isx; pisy = pisy - isy; piex = piex - iex; piey = piey - iey; pfsx = pfsx - fsx; pfsy = pfsy - fsy; pfex = pfex - fex; pfey = pfey - fey; pisx.canonicalize(); pisy.canonicalize(); piex.canonicalize(); piey.canonicalize(); pfsx.canonicalize(); pfsy.canonicalize(); pfex.canonicalize(); pfey.canonicalize(); 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(pfex, preciseCoordinates); preciseSegment_2.SetFinalEndY(pfey, preciseCoordinates); if (isBasic) { auxDms_2 = new MSegmentData2( segment.GetFaceNo(), segment.GetCycleNo(), segment.GetSegmentNo() + 1, segment.GetInsideAbove(), iex, iey, iex, iey, fsx, fsy, fex, fey); } else { auxDms_2 = new MSegmentData2( segment.GetFaceNo(), segment.GetCycleNo(), segment.GetSegmentNo() + 1, segment.GetInsideAbove(), iex, iey, iex, iey, fsx, fsy, fex, fey, 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] = { (double)broughtDown(rbb.MinD(0)), (double) broughtDown(rbb.MinD(1)), timeInterval.start.ToDouble() }; double max[3] = { (double)roundedUp(rbb.MaxD(0)), (double)roundedUp(rbb.MaxD(1)), timeInterval.end.ToDouble() }; bbox.Set(true, min, max); } /* 1.1 Methods for database operators 1.1.1 Method ~Translate()~ */ void URegionEmb2::Translate(DateTime* deltaT, double deltaX, double deltaY, DbArray* segments, DbArray* preciseSegments, DbArray* preciseCoordinates, int scaleFactor) { if (MR2_DEBUG) cerr << "URegionEmb2::Translate() called" << endl; timeInterval.start.Add(deltaT); timeInterval.end.Add(deltaT); /* First transform double paramters into fractions in order to avoid rounding errors. */ mpq_class pDeltaX = D2MPQ(deltaX); mpq_class pDeltaY = D2MPQ(deltaY); mpz_t sFactor; mpz_init(sFactor); mpq_class sFac(0); uint sfactor; if (scaleFactor < 0) { sfactor = -scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(sFactor), mpz_class(1)); } else { sfactor = scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(1), mpz_class(sFactor)); } sFac.canonicalize(); mpz_clear(sFactor); mpq_class rsFac = 1/sFac; rsFac.canonicalize(); for (int j = 0; j < this->GetSegmentsNum(); j++) { if (MR2_DEBUG) cerr << "Translating segment number " << j << " by deltaX = " << deltaX <<", deltaY = " << deltaY << " " << 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()) * sFac + pDeltaX; newInitialStartX.canonicalize(); mpq_class newInitialEndX = (psegment.GetInitialEndX(preciseCoordinates) + segment.GetInitialEndX()) * sFac + pDeltaX; newInitialEndX.canonicalize(); if ( overflowAsInt(newInitialStartX, newInitialEndX, scaleFactor) ) { cerr << "Overflow of Int values: x-translation with value " << deltaX << " is too big!" << endl; SetDefined( false ); segmentsNum = 0; return; } mpq_class newInitialStartY = (psegment.GetInitialStartY(preciseCoordinates) + segment.GetInitialStartY()) * sFac + pDeltaY; newInitialStartY.canonicalize(); mpq_class newInitialEndY = (psegment.GetInitialEndY(preciseCoordinates) + segment.GetInitialEndY()) * sFac + pDeltaY; newInitialEndY.canonicalize(); if ( overflowAsInt(newInitialStartY, newInitialEndY, scaleFactor) ) { cerr << "Overflow of Int values: y-translation with value " << deltaY << " is too big!" << endl; SetDefined( false ); segmentsNum = 0; return; } mpq_class newFinalStartX = (psegment.GetFinalStartX(preciseCoordinates) + segment.GetFinalStartX()) * sFac + pDeltaX; newFinalStartX.canonicalize(); mpq_class newFinalEndX = (psegment.GetFinalEndX(preciseCoordinates) + segment.GetFinalEndX()) * sFac + pDeltaX; newFinalEndX.canonicalize(); if ( overflowAsInt(newFinalStartX, newFinalEndX, scaleFactor) ) { cerr << "Overflow of Int values: x-translation with value " << deltaX << " is too big!" << endl; SetDefined( false ); segmentsNum = 0; return; } mpq_class newFinalStartY = (psegment.GetFinalStartY(preciseCoordinates) + segment.GetFinalStartY()) * sFac + pDeltaY; newFinalStartY.canonicalize(); mpq_class newFinalEndY = (psegment.GetFinalEndY(preciseCoordinates) + segment.GetFinalEndY()) * sFac + pDeltaY; newFinalEndY.canonicalize(); if ( overflowAsInt(newFinalStartY, newFinalEndY, scaleFactor) ) { cerr << "Overflow of Int values: y-translation with value " << deltaY << " is too big!" << endl; SetDefined( false ); segmentsNum = 0; return; } 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. */ newInitialStartX = newInitialStartX * rsFac; newInitialStartX.canonicalize(); segment.SetIsBasicSegment(true); int temp = broughtDown(newInitialStartX.get_d()); segment.SetInitialStartX(temp); psegment.SetInitialStartX( newInitialStartX - temp, preciseCoordinates); if (newInitialStartX - temp != 0) segment.SetIsBasicSegment(false); newInitialStartY = newInitialStartY * rsFac; newInitialStartY.canonicalize(); temp = broughtDown(newInitialStartY.get_d()); segment.SetInitialStartY(temp); psegment.SetInitialStartY( newInitialStartY - temp, preciseCoordinates); if (newInitialStartY - temp != 0) segment.SetIsBasicSegment(false); newInitialEndX = newInitialEndX * rsFac; newInitialEndX.canonicalize(); temp = broughtDown(newInitialEndX.get_d()); segment.SetInitialEndX(temp); psegment.SetInitialEndX( newInitialEndX - temp, preciseCoordinates); if (newInitialEndX - temp != 0) segment.SetIsBasicSegment(false); newInitialEndY = newInitialEndY * rsFac; newInitialEndY.canonicalize(); temp = broughtDown(newInitialEndY.get_d()); segment.SetInitialEndY(temp); psegment.SetInitialEndY( newInitialEndY - temp, preciseCoordinates); if (newInitialEndY - temp != 0) segment.SetIsBasicSegment(false); newFinalStartX = newFinalStartX * rsFac; newFinalStartX.canonicalize(); temp = broughtDown(newFinalStartX.get_d()); segment.SetFinalStartX(temp); psegment.SetFinalStartX( newFinalStartX - temp, preciseCoordinates); if (newFinalStartX - temp != 0) segment.SetIsBasicSegment(false); newFinalStartY = newFinalStartY * rsFac; newFinalStartY.canonicalize(); temp = broughtDown(newFinalStartY.get_d()); segment.SetFinalStartY(temp); psegment.SetFinalStartY( newFinalStartY - temp, preciseCoordinates); if (newFinalStartY - temp != 0) segment.SetIsBasicSegment(false); newFinalEndX = newFinalEndX * rsFac; newFinalEndX.canonicalize(); temp = broughtDown(newFinalEndX.get_d()); segment.SetFinalEndX(temp); psegment.SetFinalEndX( newFinalEndX - temp, preciseCoordinates); if (newFinalEndX - temp != 0) segment.SetIsBasicSegment(false); newFinalEndY = newFinalEndY * rsFac; newFinalEndY.canonicalize(); 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 ~NewScale()~ This method sets a new scalefactor for the object. */ void URegionEmb2::NewScale(int newscale, int oldscale, DbArray* segments, DbArray* preciseSegments, DbArray* preciseCoordinates) { if (MR2_DEBUG) { cerr << "URegionEmb2::NewScale() called:" << endl; cerr << "actual scaleFactor " << oldscale << endl; cerr << " new scaleFactor " << newscale << endl; } int deltaFactor = newscale - oldscale; mpz_t sFactor; mpz_init(sFactor); mpq_class sFac(0); uint sfactor; if (deltaFactor < 0) { sfactor = -deltaFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(1), mpz_class(sFactor)); } else { sfactor = deltaFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(sFactor), mpz_class(1)); } sFac.canonicalize(); mpz_clear(sFactor); minIntx = 0; minInty = 0; maxIntx = 0; maxInty = 0; minPrecx = mpq_class(0); minPrecy = mpq_class(0); maxPrecx = mpq_class(0); maxPrecy = mpq_class(0); for (int j = 0; j < this->GetSegmentsNum(); j++) { if (MR2_DEBUG) cerr << "Scaling segment " << j << ", factor is: " << sFac << 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()) * sFac; newInitialStartX.canonicalize(); mpq_class newInitialStartY = (psegment.GetInitialStartY(preciseCoordinates) + segment.GetInitialStartY()) * sFac; newInitialStartY.canonicalize(); if ( overflowAsInt(newInitialStartX, newInitialStartY) ) { SetDefined(false); segmentsNum = 0; return; } mpq_class newInitialEndX = (psegment.GetInitialEndX(preciseCoordinates) + segment.GetInitialEndX()) * sFac; newInitialEndX.canonicalize(); mpq_class newInitialEndY = (psegment.GetInitialEndY(preciseCoordinates) + segment.GetInitialEndY()) * sFac; newInitialEndY.canonicalize(); if ( overflowAsInt(newInitialEndX, newInitialEndY) ) { SetDefined(false); segmentsNum = 0; return; } mpq_class newFinalStartX = (psegment.GetFinalStartX(preciseCoordinates) + segment.GetFinalStartX()) * sFac; newFinalStartX.canonicalize(); mpq_class newFinalStartY = (psegment.GetFinalStartY(preciseCoordinates) + segment.GetFinalStartY()) * sFac; newFinalStartY.canonicalize(); if ( overflowAsInt(newFinalStartX, newFinalStartY) ) { SetDefined(false); segmentsNum = 0; return; } mpq_class newFinalEndX = (psegment.GetFinalEndX(preciseCoordinates) + segment.GetFinalEndX()) * sFac; newFinalEndX.canonicalize(); mpq_class newFinalEndY = (psegment.GetFinalEndY(preciseCoordinates) + segment.GetFinalEndY()) * sFac; newFinalEndY.canonicalize(); if ( overflowAsInt(newFinalEndX, newFinalEndY) ) { SetDefined(false); segmentsNum = 0; return; } 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()); if (temp > maxIntx) maxIntx = temp; if (temp < minIntx) minIntx = temp; segment.SetInitialStartX(temp); psegment.SetInitialStartX( newInitialStartX - temp, preciseCoordinates); if (newInitialStartX - temp != 0) segment.SetIsBasicSegment(false); temp = broughtDown(newInitialStartY.get_d()); if (temp > maxInty) maxInty = temp; if (temp < minInty) minInty = temp; segment.SetInitialStartY(temp); psegment.SetInitialStartY( newInitialStartY - temp, preciseCoordinates); if (newInitialStartY - temp != 0) segment.SetIsBasicSegment(false); temp = broughtDown(newInitialEndX.get_d()); if (temp > maxIntx) maxIntx = temp; if (temp < minIntx) minIntx = temp; segment.SetInitialEndX(temp); psegment.SetInitialEndX( newInitialEndX - temp, preciseCoordinates); if (newInitialEndX - temp != 0) segment.SetIsBasicSegment(false); temp = broughtDown(newInitialEndY.get_d()); if (temp > maxInty) maxInty = temp; if (temp < minInty) minInty = temp; segment.SetInitialEndY(temp); psegment.SetInitialEndY( newInitialEndY - temp, preciseCoordinates); if (newInitialEndY - temp != 0) segment.SetIsBasicSegment(false); temp = broughtDown(newFinalStartX.get_d()); if (temp > maxIntx) maxIntx = temp; if (temp < minIntx) minIntx = temp; segment.SetFinalStartX(temp); psegment.SetFinalStartX( newFinalStartX - temp, preciseCoordinates); if (newFinalStartX - temp != 0) segment.SetIsBasicSegment(false); temp = broughtDown(newFinalStartY.get_d()); if (temp > maxInty) maxInty = temp; if (temp < minInty) minInty = temp; segment.SetFinalStartY(temp); psegment.SetFinalStartY( newFinalStartY - temp, preciseCoordinates); if (newFinalStartY - temp != 0) segment.SetIsBasicSegment(false); temp = broughtDown(newFinalEndX.get_d()); if (temp > maxIntx) maxIntx = temp; if (temp < minIntx) minIntx = temp; segment.SetFinalEndX(temp); psegment.SetFinalEndX( newFinalEndX - temp, preciseCoordinates); if (newFinalEndX - temp != 0) segment.SetIsBasicSegment(false); temp = broughtDown(newFinalEndY.get_d()); if (temp > maxInty) maxInty = temp; if (temp < minInty) minInty = temp; 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()~ This method scales the object by ~deltaX~ and ~deltaY~. */ void URegionEmb2::Scale(double deltaX, double deltaY, DbArray* segments, DbArray* preciseSegments, DbArray* preciseCoordinates) { if (MR2_DEBUG) cerr << "URegionEmb2::Scale() called" << endl; /* First transform the double paramters into fractions in order to avoid rounding errors. */ mpq_class pDeltaX = D2MPQ(deltaX); mpq_class pDeltaY = D2MPQ(deltaY); 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; newInitialStartX.canonicalize(); mpq_class newInitialEndX = (psegment.GetInitialEndX(preciseCoordinates) + segment.GetInitialEndX()) * pDeltaX; newInitialEndX.canonicalize(); if ( overflowAsInt(newInitialStartX, newInitialEndX) ) { cerr << "Overflow of Int values: x-factor with value " << deltaX << " is too big!" << endl; SetDefined( false ); segmentsNum = 0; return; } mpq_class newInitialStartY = (psegment.GetInitialStartY(preciseCoordinates) + segment.GetInitialStartY()) * pDeltaY; newInitialStartY.canonicalize(); mpq_class newInitialEndY = (psegment.GetInitialEndY(preciseCoordinates) + segment.GetInitialEndY()) * pDeltaY; newInitialEndY.canonicalize(); if ( overflowAsInt(newInitialStartY, newInitialEndY) ) { cerr << "Overflow of Int values: y-factor with value " << deltaY << " is too big!" << endl; SetDefined( false ); segmentsNum = 0; return; } mpq_class newFinalStartX = (psegment.GetFinalStartX(preciseCoordinates) + segment.GetFinalStartX()) * pDeltaX; newFinalStartX.canonicalize(); mpq_class newFinalEndX = (psegment.GetFinalEndX(preciseCoordinates) + segment.GetFinalEndX()) * pDeltaX; newFinalEndX.canonicalize(); if ( overflowAsInt(newFinalStartX, newFinalEndX) ) { cerr << "Overflow of Int values: x-factor with value " << deltaX << " is too big!" << endl; SetDefined( false ); segmentsNum = 0; return; } mpq_class newFinalStartY = (psegment.GetFinalStartY(preciseCoordinates) + segment.GetFinalStartY()) * pDeltaY; newFinalStartY.canonicalize(); mpq_class newFinalEndY = (psegment.GetFinalEndY(preciseCoordinates) + segment.GetFinalEndY()) * pDeltaY; newFinalEndY.canonicalize(); if ( overflowAsInt(newFinalStartY, newFinalEndY) ) { cerr << "Overflow of Int values: y-factor with value " << deltaY << " is too big!" << endl; SetDefined( false ); segmentsNum = 0; return; } 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 Region2 instance by evaluating the URegionEmb2 instance at one single instant t. */ void URegionEmb2::TemporalFunction( const DbArray* segments, const DbArray* preciseSegments, const DbArray* preciseCoordinates, const DbArray* preciseInstants, const Instant& t, const mpq_class& preciseInstant, const int scaleFactor, Region2& 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 fuer 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; } mpz_t sFactor; mpz_init(sFactor); mpq_class sFac(0); uint sfactor; if (scaleFactor < 0) { sfactor = -scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(sFactor), mpz_class(1)); } else { sfactor = scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(1), mpz_class(sFactor)); } sFac.canonicalize(); mpz_clear(sFactor); pxs = pxs * sFac; pys = pys * sFac; pxe = pxe * sFac; pye = pye * sFac; if (MR2_DEBUG){ cerr << "URegionEmb2::TemporalFunction() " << "next value is (" << pxs << ", " << pys << ", " << pxe << ", " << pye << ")" << endl; } if ( cmp(pxs, pxe) == 0 && cmp(pys, pye) == 0 ) { 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; } Reg2PrecisePoint s(pxs, pys); Reg2PrecisePoint e(pxe, pye); if ( 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; } Reg2PreciseHalfSegment 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; } res += hs; hs.SetLeftDomPoint(!hs.IsLeftDomPoint()); if (MR2_DEBUG){ cerr << "URegionEmb2::TemporalFunction() " << "Adding hs=" << hs << endl; } res += hs; } //Try region calculation res.SetScaleFactor(scaleFactor, false); res.EndBulkLoad(); if ( !res.IsDefined() || !res.validateRegion2() ) { if (MR2_DEBUG) { cerr << "URegionEmb2::TemporalFunction() failed. " << "EndBulkLoad method did not return a valid region unit." << endl; } res.Clear(); res.SetDefined(false); return; } if (MR2_DEBUG){ for (int i = 0; i < res.Size(); i++) { Reg2PreciseHalfSegment hs; res.Get(i, hs); cerr << "URegionEmb2::TemporalFunction() segment #" << i << " lp=(" << hs.GetLeftPoint().x << ", " << hs.GetLeftPoint().y << ") rp=(" << hs.GetRightPoint().x << ", " << hs.GetRightPoint().y << ") 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 { if (timeInterval.IsValid() && ur.timeInterval.IsValid()) return (timeInterval == ur.timeInterval); return false; } /* 1.1.1 Method ~Before()~ */ bool URegionEmb2::Before(const URegionEmb2& ur) const { if (timeInterval.IsValid() && ur.timeInterval.IsValid()) return timeInterval.Before(ur.timeInterval); return false; } /* 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* 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* preciseSegments, int pos, PreciseMSegmentData& pdms) const { preciseSegments->Get(segmentsStartPos+pos, pdms); } /* 1.1.1 Method ~PutSegment()~ */ void URegionEmb2::PutSegment( DbArray* 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* 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* 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* 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* segments, DbArray* preciseSegments, DbArray* preciseCoordinates, DbArray* preciseInstants, unsigned int segmentsStartPos, int scaleFactor) { if (MR2_DEBUG) cerr << "InURegionEmbedded2() called, segmentsStartPos = " << segmentsStartPos << endl; if (nl->ListLength(instance) <= 1) { cerr << "uregion not in format " << "( )" << endl; return 0; } if (MR2_DEBUG) cerr << "InURegionEmbedded() ( ) 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 i 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 instant component and maybe some fraction that will later be added to the precise time interval given in nl->fifth(interval). */ bool correct; Instant* start=0; Instant* end=0; mpq_class pstart(0); mpq_class pend(0); mpq_class reststart(0); mpq_class restend(0); bool hasPreciseRest = false; bool hasPreciseRepresentation = false; if (nl->AtomType(nl->First(interval)) == IntType) { start = new Instant(nl->IntValue(nl->First(interval)), 0, datetime::instanttype); } else { start = (Instant *) InInstant(nl->TheEmptyList(), nl->First(interval), errorPos, errorInfo, correct).addr; if (!correct) { cerr << "uregion interval invalid start" <<" time" << endl; if(start) delete start; return 0; } if (nl->AtomType(nl->First(interval)) == RealType) pstart = D2MPQ(nl->RealValue(nl->First(interval))) - instant2MPQ(*start); if (cmp(reststart, 0) > 0) hasPreciseRest = true; } if (nl->AtomType(nl->Second(interval)) == IntType) { end = new Instant(nl->IntValue(nl->Second(interval)), 0, datetime::instanttype); } else { end = (Instant *) InInstant(nl->TheEmptyList(), nl->Second(interval), errorPos, errorInfo, correct).addr; if (!correct) { cerr << "uregion interval invalid end time" << endl; delete start; delete end; return 0; } if (nl->AtomType(nl->Second(interval)) == RealType) pend = D2MPQ(nl->RealValue(nl->Second(interval))) - instant2MPQ(*end); if (cmp(restend, 0) > 0) hasPreciseRest = true; } bool lc = nl->BoolValue(nl->Third(interval)); bool rc = nl->BoolValue(nl->Fourth(interval)); if (start->CompareTo((const Instant*)end) > 0) { cerr << "uregion invalid interval, starttime is after endtine!\n" << "start: " << *start << " end: " << *end << endl; delete start; delete end; return 0; } /* 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); /* 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) { try { textTypeToGmpType1(nl->First(preciseInterval), pstart); textTypeToGmpType1(nl->Second(preciseInterval), pend); } catch (invalid_argument& e) { cerr << endl << "--------------------------------" << "-------------------------------" << endl << "Checking time interval failed." << endl << e.what() << endl << "----------------------------------" << "-----------------------------" << endl; delete start; delete end; return 0; } hasPreciseRepresentation = true; } if (hasPreciseRepresentation) { mpq_class precstart = instant2MPQ(*start) + reststart + pstart; precTimeToInstant(precstart, *start, reststart); mpq_class precend = instant2MPQ(*end) + restend + pend; precTimeToInstant(precend, *end, restend); hasPreciseRest = true; } if (hasPreciseRest) { preciseTimeInterval.SetPreciseInitialInstant(reststart, preciseInstants); preciseTimeInterval.SetPreciseFinalInstant(restend, preciseInstants); } /* Now we check the syntax of the time interval again. If we have equal instant values for the start and the end time, we check if it is correct considering the precise part of it. */ if (start->CompareTo((const Instant*)end) == 0) { if (MR2_DEBUG) cerr << "Time interval with start and end equal" << endl << "start is " << *start << " end is " << *end << endl << "Check with precise values..." << endl; if (MR2_DEBUG) cerr << "Precise start is " << reststart << endl << "Precise end is " << restend << endl; pstart = instant2MPQ(*start) + reststart; pend = instant2MPQ(*end) + restend; if ( (cmp(pstart, pend) > 0) || (cmp(pstart, pend) == 0 && !(lc && rc)) ) { cerr << "uregion invalid interval, start: " << *start << " end: " << *end << " precise parts: " << reststart << " and " << restend << endl; delete start; delete end; return 0; } } Interval 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 region2 and relying on the algorithms there for syntax check. */ URegionEmb2* uregion = new URegionEmb2( tinterval, preciseTimeInterval, segmentsStartPos); unsigned int faceno = 0; unsigned int partnerno = 0; ListExpr faces = nl->Second(instance); Region2 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. */ Region2 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. */ if (prevPoint != 0 && !uregion->AddSegment(segments, preciseSegments, preciseCoordinates, preciseInstants, cr, rDir, faceno, cycleno, pointno++, partnerno++, intervalLen, prevPoint, point, scaleFactor)) { cerr << "uregion's segment checks failed" << endl; delete uregion; return 0; } prevPoint = point; cyclepoints = nl->Rest(cyclepoints); } if (!uregion->AddSegment(segments, preciseSegments, preciseCoordinates, preciseInstants, cr, rDir, faceno, cycleno, pointno++, partnerno++, intervalLen, prevPoint, firstPoint, scaleFactor)) { cerr << "uregion's segment checks failed " << "with closing segment" << endl; delete uregion; return 0; } rDir.SetScaleFactor(scaleFactor, false); rDir.EndBulkLoad(true, true, false, false); bool direction = rDir.GetCycleDirection(); int h = cr.Size()-(rDir.Size()*2); int i = initialSegmentsNum; while (h < cr.Size()) { Reg2PreciseHalfSegment 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.SetScaleFactor(scaleFactor, false); cr.EndBulkLoad(); if (!cr.IsDefined() || !cr.validateRegion2()) { if (MR2_DEBUG) { cerr << "InURegionEmbedded2() " << "validation witg region2 failed! " << endl; delete uregion; return 0; } } 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; } /* 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* segments, DbArray* preciseSegments, DbArray* preciseCoordinates, DbArray* preciseInstants, int scaleFactor) { 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 realized 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; gmpTypeToTextType1(preciseInitialStartX, l1); gmpTypeToTextType1(preciseInitialStartY, l2); gmpTypeToTextType1(preciseFinalStartX, l3); gmpTypeToTextType1(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; gmpTypeToTextType1( pInt.GetPreciseInitialInstant(preciseInstants), pStart); gmpTypeToTextType1( 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. */ bool URegionEmb2::AddSegment( DbArray* segments, DbArray* preciseSegments, DbArray* preciseCoordinates, DbArray* preciseInstants, Region2& cr, Region2& rDir, unsigned int faceno, unsigned int cycleno, unsigned int segmentno, unsigned int partnerno, DateTime& intervalLen, ListExpr start, ListExpr end, int scaleFactor) { 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 " + "( )"); } 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 " + "( )"); } /* 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) { textTypeToGmpType1(nl->First( nl->Fifth(start)), piStartX); textTypeToGmpType1(nl->Second( nl->Fifth(start)), piStartY); textTypeToGmpType1(nl->Third( nl->Fifth(start)), pfStartX); textTypeToGmpType1(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) { textTypeToGmpType1(nl->First( nl->Fifth(end)), piEndX); textTypeToGmpType1(nl->Second( nl->Fifth(end)), piEndY); textTypeToGmpType1(nl->Third( nl->Fifth(end)), pfEndX); textTypeToGmpType1(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. */ Reg2GridPoint point1(dms.GetInitialStartX(), dms.GetInitialStartY(), dms.GetIsBasicSegment()); Reg2GridPoint point2(dms.GetInitialEndX(), dms.GetInitialEndY(), dms.GetIsBasicSegment()); Reg2GridPoint point3(dms.GetFinalStartX(), dms.GetFinalStartY(), dms.GetIsBasicSegment()); Reg2GridPoint point4(dms.GetFinalEndX(), dms.GetFinalEndY(), dms.GetIsBasicSegment()); GridPointSegment segment1(point1, point2); GridPointSegment segment2(point3, point4); Reg2GridPoint point5(existingDms.GetInitialStartX(), existingDms.GetInitialStartY(), existingDms.GetIsBasicSegment()); Reg2GridPoint point6(existingDms.GetInitialEndX(), existingDms.GetInitialEndY(), existingDms.GetIsBasicSegment()); Reg2GridPoint point7(existingDms.GetFinalStartX(), existingDms.GetFinalStartY(), existingDms.GetIsBasicSegment()); Reg2GridPoint 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. Therefore we need to add coordinates of precise and integer representation to get the absolute values. */ Reg2PrecisePoint ppoint1 (pdms.GetInitialStartX (preciseCoordinates)+ dms.GetInitialStartX(), pdms.GetInitialStartY (preciseCoordinates)+ dms.GetInitialStartY()); Reg2PrecisePoint ppoint2(pdms.GetInitialEndX (preciseCoordinates) +dms.GetInitialEndX(), pdms.GetInitialEndY (preciseCoordinates) +dms.GetInitialEndY()); Reg2PrecisePoint ppoint3(pdms.GetFinalStartX (preciseCoordinates) +dms.GetFinalStartX(), pdms.GetFinalStartY (preciseCoordinates) +dms.GetFinalStartY()); Reg2PrecisePoint ppoint4(pdms.GetFinalEndX (preciseCoordinates) +dms.GetFinalEndX(), pdms.GetFinalEndY (preciseCoordinates) +dms.GetFinalEndY()); PreciseSegment psegment1(ppoint1, ppoint2); PreciseSegment psegment2(ppoint3, ppoint4); PreciseTrapezium ptrapezium1(psegment1, psegment2); Reg2PrecisePoint ppoint5 (existingPdms.GetInitialStartX (preciseCoordinates)+ existingDms.GetInitialStartX(), existingPdms.GetInitialStartY (preciseCoordinates)+ existingDms.GetInitialStartY()); Reg2PrecisePoint ppoint6 (existingPdms.GetInitialEndX (preciseCoordinates)+ existingDms.GetInitialEndX(), existingPdms.GetInitialEndY (preciseCoordinates)+ existingDms.GetInitialEndY()); Reg2PrecisePoint ppoint7 (existingPdms.GetFinalStartX (preciseCoordinates)+ existingDms.GetFinalStartX(), existingPdms.GetFinalStartY (preciseCoordinates)+ existingDms.GetFinalStartY()); Reg2PrecisePoint 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 region2 check and direction computation. */ double t = 0.5; mpq_class pisx = dms.GetInitialStartX() + pdms.GetInitialStartX(preciseCoordinates); mpq_class pisy = dms.GetInitialStartY() + pdms.GetInitialStartY(preciseCoordinates); mpq_class piex = dms.GetInitialEndX() + pdms.GetInitialEndX(preciseCoordinates); mpq_class piey = dms.GetInitialEndY() + pdms.GetInitialEndY(preciseCoordinates); mpq_class pfsx = dms.GetFinalStartX() + pdms.GetFinalStartX(preciseCoordinates); mpq_class pfsy = dms.GetFinalStartY() + pdms.GetFinalStartY(preciseCoordinates); mpq_class pfex = dms.GetFinalEndX() + pdms.GetFinalEndX(preciseCoordinates); mpq_class pfey = dms.GetFinalEndY() + pdms.GetFinalEndY(preciseCoordinates); if (dms.GetInitialStartX() > maxIntx) maxIntx = dms.GetInitialStartX(); if (dms.GetInitialStartY() > maxInty) maxInty = dms.GetInitialStartY(); if (dms.GetInitialEndX() > maxIntx) maxIntx = dms.GetInitialEndX(); if (dms.GetInitialEndY() > maxInty) maxInty = dms.GetInitialEndY(); if (dms.GetFinalStartX() > maxIntx) maxIntx = dms.GetFinalStartX(); if (dms.GetFinalStartY() > maxInty) maxInty = dms.GetFinalStartY(); if (dms.GetFinalEndX() > maxIntx) maxIntx = dms.GetFinalEndX(); if (dms.GetFinalEndY() > maxInty) maxInty = dms.GetFinalEndY(); if (dms.GetInitialStartX() < minIntx) minIntx = dms.GetInitialStartX(); if (dms.GetInitialStartY() < minInty) minInty = dms.GetInitialStartY(); if (dms.GetInitialEndX() < minIntx) minIntx = dms.GetInitialEndX(); if (dms.GetInitialEndY() < minInty) minInty = dms.GetInitialEndY(); if (dms.GetFinalStartX() < minIntx) minIntx = dms.GetFinalStartX(); if (dms.GetFinalStartY() < minInty) minInty = dms.GetFinalStartY(); if (dms.GetFinalEndX() < minIntx) minIntx = dms.GetFinalEndX(); if (dms.GetFinalEndY() < minInty) minInty = dms.GetFinalEndY(); mpq_class pxs = pisx + (pfsx - pisx)*t; mpq_class pys = pisy + (pfsy - pisy)*t; mpq_class pxe = piex + (pfex - piex)*t; mpq_class pye = piey + (pfey - piey)*t; mpz_t sFactor; mpz_init(sFactor); mpq_class sFac(0); uint sfactor; if (scaleFactor < 0) { sfactor = -scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(sFactor), mpz_class(1)); } else { sfactor = scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(1), mpz_class(sFactor)); } sFac.canonicalize(); mpz_clear(sFactor); pisx = pisx * sFac; pisy = pisy * sFac; piex = piex * sFac; piey = piey * sFac; pfsx = pfsx * sFac; pfsy = pfsy * sFac; pfex = pfex * sFac; pfey = pfey * sFac; if (cmp(pisx, maxPrecx) > 0) maxPrecx = pisx; if (cmp(pisy, maxPrecy) > 0) maxPrecy = pisy; if (cmp(piex, maxPrecx) > 0) maxPrecx = piex; if (cmp(piey, maxPrecy) > 0) maxPrecy = piey; if (cmp(pfsx, maxPrecx) > 0) maxPrecx = pfsx; if (cmp(pfsy, maxPrecy) > 0) maxPrecy = pfsy; if (cmp(pfex, maxPrecx) > 0) maxPrecx = pfex; if (cmp(pfey, maxPrecy) > 0) maxPrecy = pfey; if (cmp(pisx, minPrecx) < 0) minPrecx = pisx; if (cmp(pisy, minPrecy) < 0) minPrecy = pisy; if (cmp(piex, minPrecx) < 0) minPrecx = piex; if (cmp(piey, minPrecy) < 0) minPrecy = piey; if (cmp(pfsx, minPrecx) < 0) minPrecx = pfsx; if (cmp(pfsy, minPrecy) < 0) minPrecy = pfsy; if (cmp(pfex, minPrecx) < 0) minPrecx = pfex; if (cmp(pfey, minPrecy) < 0) minPrecy = pfey; pxs = pxs * sFac; pys = pys * sFac; pxe = pxe * sFac; pye = pye * sFac; Reg2PrecisePoint s(pxs, pys); Reg2PrecisePoint e(pxe, pye); /* Here we need an extra check, because HalfSegment creation will lead to a failed assertion if start and end point are equal. */ if ( 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: (" << pxs << ", " << pys << ")" << endl << "End point: (" << pxe << ", " << pye << ")" << endl << "Try input with larger coordinates " << "and scale afterwards with scale operator!" << endl << "--------------------------------------------------" << endl; return false; } Reg2PreciseHalfSegment 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 << " (" << pxs << ", " << pys << ")-(" << pxe << ", " << pye << ") ia=" << hs.attr.insideAbove << endl; 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() ? (double)dms.GetInitialStartX() : (double)dms.GetFinalStartX(), dms.GetInitialStartY() < dms.GetFinalStartY() ? (double)dms.GetInitialStartY() : (double)dms.GetFinalStartY(), timeInterval.start.ToDouble() }; double max[3] = { dms.GetInitialStartX() > dms.GetFinalStartX() ? (double) dms.GetInitialStartX()+1 : (double)dms.GetFinalStartX()+1, dms.GetInitialStartY() > dms.GetFinalStartY() ? (double)dms.GetInitialStartY()+1 : (double)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.1 Relative positions of points and segments 1.1.1 Function ~pointPositionToSegment()~ Returns an integer value indicating the position of point $(x, y)$ in relation to the segment spanned by the points $(p1x, p1y)$ and $(p2x, p2y)$. The values have the following meaning: value 0: the point is on the segment, also if the segment is degenerated to a point (in this case all three points are equal); value 1: the point is on the straight line that carry the segment, the point is not on the segment itself, but left of it; value 2: the point is left or above the segment, this matches the definition of the ~insideAbove~ attribute; value 3: the point is on the straight line that carry the segment, the point is not on the segment itself, but right of it ; value 4: the point is right or under the segment; value 5: the segment is degenerated to a point and the single point is elsewhere (they are unequal); value -1: an error occured - this should never happen. */ static int pointPositionToSegment(mpq_class x, mpq_class y, mpq_class p1x, mpq_class p1y, mpq_class p2x, mpq_class p2y) { if (MR2_DEBUG) cerr << "pointPositionToSegment() called p=(" << x << " " << y << ") p1=(" << p1x << " " << p1y << ") p2=(" << p2x << " " << p2y << ")" << endl; if (cmp(p1x, p2x) == 0) //vertical line { if (MR2_DEBUG) cerr << "pointPositionToSegment() p1x=p2x" << endl; if (cmp(p1x, x) == 0) // point is on segment line { if (cmp(p1y, p2y) < 0) { if (cmp(y, p1y) < 0) return 1; if (cmp(p2y, y) < 0) return 3; return 0; } else if (cmp(p1y, p2y) > 0) { if (cmp(y, p2y) < 0) return 3; if (cmp(p1y, y) < 0) return 1; return 0; } else // segment is degenerated to point { if (cmp(p1y, y) == 0) return 0; // point is on degenerated line return 5; } } else if (cmp(p1x, x) < 0) return 4; else return 2; } else if (cmp(p1y, p2y) == 0) //horizontal line { if (MR2_DEBUG) cerr << "pointPositionToSegment() p1y=p2y" << endl; if (cmp(p1y, y) == 0) // point is on segment line { if (cmp(p1x, p2x) < 0) { if (cmp(x, p1x) < 0) return 1; if (cmp(p2x, x) < 0) return 3; return 0; } else if (cmp(p1x, p2x) > 0) { if (cmp(x, p2x) < 0) return 3; if (cmp(p1x, x) < 0) return 1; return 0; } } else if (cmp(p1y, y) > 0) return 4; else return 2; } else { if (MR2_DEBUG) cerr << "pointPositionToSegment() other" << endl; mpq_class t = (mpq_class(x) - p1x) / (p2x - p1x); mpq_class py = p1y + (p2y - p1y) * t; if (MR2_DEBUG) cerr << "pointPositionToSegment() py=" << py << endl; if (cmp(py, y) == 0) // point is on segment line { if (cmp(p1x, p2x) < 0) { if (cmp(x, p1x) < 0) return 1; if (cmp(p2x, x) < 0) return 3; return 0; } else if (cmp(p1x, p2x) > 0) { if (cmp(x, p2x) < 0) return 3; if (cmp(p1x, x) < 0) return 1; return 0; } } else if (cmp(py, y) > 0) // return 4; else return 2; } return -1; } /* Additional interfaces for the use of method ~pointPositionToSegment()~ */ static int pointPositionToSegment(double x, double y, mpq_class p1x, mpq_class p1y, mpq_class p2x, mpq_class p2y) { return pointPositionToSegment(mpq_class(x), mpq_class(y), p1x, p1y, p2x, p2y); } static int pointPositionToSegment(Reg2PrecisePoint p, Reg2PrecisePoint p1, Reg2PrecisePoint p2) { return pointPositionToSegment(p.x, p.y, p1.x, p1.y, p2.x, p2.y); } /* 1.1.1 Function ~pointAboveSegment()~ Returns ~true~ if point $(x, y)$ is located left or above or on the segment spanned by the points $(p1x, p1y)$ and $(p2x, p2y)$. This matches the definition of the ~insideAbove~ attribute in ~Region~ and ~URegion~ instances. */ bool pointAboveSegment(double x, double y, mpq_class p1x, mpq_class p1y, mpq_class p2x, mpq_class p2y) { if (MR2_DEBUG) cerr << "pointAboveSegment() called p=(" << x << " " << y << ") p1=(" << p1x << " " << p1y << ") p2=(" << p2x << " " << p2y << ")" << endl; return (pointPositionToSegment(x, y, p1x, p1y, p2x, p2y) < 4); } /* 1.1 Helper methods for ~RestrictedIntersection()~ 1.1.1 Method ~Plumbline()~ */ unsigned int URegionEmb2::Plumbline(const DbArray* segments, const DbArray* preciseSegments, const DbArray* preciseCoordinates, const DbArray* preciseInstants, const int scaleFactor, const UPoint& up, const precTimeInterval& iv) const { if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() called" << endl; /* Since we know that ~up~ is not intersecting with any of the segments, we can pick any time in ~iv~ to examine ~up~ and the segments. We pick the start time of the interval: */ if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() iv.start=" << iv.start << " iv.end=" << iv.end << endl; UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() p0=(" << rUp.p0.GetX() << " " << rUp.p0.GetY() << ") p1=(" << rUp.p1.GetX() << " " << rUp.p1.GetY() << ")" << endl; double dx = rUp.p0.GetX(); double dy = rUp.p0.GetY(); mpq_class x = mpq_class(rUp.p0.GetX()); mpq_class y = mpq_class(rUp.p0.GetY()); if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() x=" << x << " y=" << y << endl; /* ~num~ is used to count the segments above ~(x, y)~. */ unsigned int num = 0; /* Go through all segments... */ precTimeInterval origiv(timeInterval, pInterval, preciseInstants); mpq_class pti(0); if (cmp(origiv.start, origiv.end) != 0 ) { pti = (iv.start - origiv.start) / (origiv.end - origiv.start); pti.canonicalize(); } mpz_t sFactor; mpz_init(sFactor); mpq_class sFac(0); uint sfactor; if (scaleFactor < 0) { sfactor = -scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(sFactor), mpz_class(1)); } else { sfactor = scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(1), mpz_class(sFactor)); } sFac.canonicalize(); mpz_clear(sFactor); for (unsigned int i = 0; i < segmentsNum; i++) { if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() segment #" << i << endl; MSegmentData2 dms; segments->Get(segmentsStartPos+i, &dms); double dp1x = dms.GetInitialStartX() + (dms.GetFinalStartX() - dms.GetInitialStartX() ) * pti.get_d(); double dp1y = dms.GetInitialStartY() + (dms.GetFinalStartY() - dms.GetInitialStartY() ) * pti.get_d(); double dp2x = dms.GetInitialEndX() + (dms.GetFinalEndX() - dms.GetInitialEndX() ) * pti.get_d(); double dp2y = dms.GetInitialEndY() + (dms.GetFinalEndY() - dms.GetInitialEndY() ) * pti.get_d(); double dMinX = dp1x < dp2x ? dp1x : dp2x; double dMaxX = dp1x > dp2x ? dp1x : dp2x; double dMaxY = dp1y > dp2y ? dp1y : dp2y; dMaxX += 1.; dMaxY += 1.; dMinX *= sFac.get_d(); dMaxX *= sFac.get_d(); dMaxY *= sFac.get_d(); if ( (dx < dMinX) ||(dMaxX < dx) ||(dMaxY < dy) ) { continue; } PreciseMSegmentData pdms; preciseSegments->Get(segmentsStartPos+i, &pdms); mpq_class p1x = dms.GetInitialStartX() + pdms.GetInitialStartX(preciseCoordinates) + (dms.GetFinalStartX() + pdms.GetFinalStartX(preciseCoordinates) - (dms.GetInitialStartX() + pdms.GetInitialStartX(preciseCoordinates)))*pti; mpq_class p1y = dms.GetInitialStartY() + pdms.GetInitialStartY(preciseCoordinates) + (dms.GetFinalStartY() + pdms.GetFinalStartY(preciseCoordinates) - (dms.GetInitialStartY() + pdms.GetInitialStartY(preciseCoordinates)))*pti; mpq_class p2x = dms.GetInitialEndX() + pdms.GetInitialEndX(preciseCoordinates) + (dms.GetFinalEndX() + pdms.GetFinalEndX(preciseCoordinates) - (dms.GetInitialEndX() + pdms.GetInitialEndX(preciseCoordinates)))*pti; mpq_class p2y = dms.GetInitialEndY() + pdms.GetInitialEndY(preciseCoordinates) + (dms.GetFinalEndY() + pdms.GetFinalEndY(preciseCoordinates) - (dms.GetInitialEndY() + pdms.GetInitialEndY(preciseCoordinates)))*pti; p1x = p1x * sFac; p1x.canonicalize(); p1y = p1y * sFac; p1y.canonicalize(); p2x = p2x * sFac; p2x.canonicalize(); p2y = p2y * sFac; p2y.canonicalize(); if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() p1x=" << p1x << " p1y=" << p1y << " p2x=" << p2x << " p2y=" << p2y << endl; if (cmp(p1x, p2x) == 0) { /* Ignore vertical segments. */ if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() " << "vertical, ignored" << endl; } else if (cmp(p1x, x) == 0 && cmp(y, p1y) <= 0) { /* ~(x, y)~ is one of the endpoints. Only count it if it is the right endpoint. */ if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() plumbline " << "through start point" << endl; if (cmp(p1x, p2x) > 0) { if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() counted" << endl; num++; } else if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() ignored" << endl; } else if (cmp(p2x, x) == 0 && cmp(y, p2y) <= 0) { /* ~(x, y)~ is one of the endpoints. Only count it if it is the right endpoint. */ if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() plumbline " << "through end point" << endl; if (cmp(p1x, p2x) < 0) { if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() counted" << endl; num++; } else if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() ignored" << endl; } else if ((cmp(p1x, p2x) < 0 && cmp(p1x, x) < 0 && cmp(x, p2x) < 0) || (cmp(p2x, p1x) < 0 && cmp(p2x, x) < 0 && cmp(x, p1x) < 0)) // x between(p1x, p2x) { /* ~(x, y)~ is in the same ~x~-range as the segment. Count it if the segment is above ~(x, y)~. */ if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() checking for " << "intersection" << endl; if (MR2_DEBUG) { cerr << "URegionEmb2::Plumbline() cmp(p1x, x)=" << cmp(p1x, x) << endl; cerr << "URegionEmb2::Plumbline() cmp(p2x, x)=" << cmp(p2x, x) << endl; } // solve p1x+(p2x-p1x)*s = x mpq_class s = (x - p1x)/(p2x - p1x); mpq_class ys = p1y + (p2y - p1y)*s; if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() ys=" << ys << endl; if (cmp(y, ys) <= 0) { if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() below" << endl; num++; } else if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() not below" << endl; } else { /* ~(x, y)~ is not below the segment. */ if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() x not between " << "p1x, p1y, ignored" << endl; } if (MR2_DEBUG) cerr << "URegionEmb2::Plumbline() num=" << num << endl; } return num; } /* 1.1.1 Method ~RestrictedIntersectionFind()~ */ void URegionEmb2::RestrictedIntersectionFind( const DbArray* segments, const DbArray* preciseSegments, const DbArray* preciseCoordinates, const DbArray* preciseInstants, const int scaleFactor, const UPoint& up, const precTimeInterval& iv, vector& vtsi) const { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() called" << endl; if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() interval " << iv.start << " to " << iv.end << endl; UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); double p1x = rUp.p0.GetX(); double p2x = rUp.p1.GetX(); double p1y = rUp.p0.GetY(); double p2y = rUp.p1.GetY(); double lMinX = p1x < p2x ? p1x : p2x; double lMaxX = p1x > p2x ? p1x : p2x; double lMinY = p1y < p2y ? p1y : p2y; double lMaxY = p1y > p2y ? p1y : p2y; precTimeInterval origiv(timeInterval, pInterval, preciseInstants); mpq_class pti(0); mpq_class ptf(0); if (cmp(origiv.start, origiv.end) != 0 ) { pti = (iv.start - origiv.start) / (origiv.end - origiv.start); pti.canonicalize(); ptf = (iv.end -origiv.start) / (origiv.end - origiv.start); ptf.canonicalize(); } mpz_t sFactor; mpz_init(sFactor); mpq_class sFac(0); uint sfactor; if (scaleFactor < 0) { sfactor = -scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(sFactor), mpz_class(1)); } else { sfactor = scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(1), mpz_class(sFactor)); } sFac.canonicalize(); mpz_clear(sFactor); for (unsigned int i = 0; i < segmentsNum; i++) { MSegmentData2 dms; segments->Get(segmentsStartPos+i, &dms); double dl1p1x = dms.GetInitialStartX() + (dms.GetFinalStartX() - dms.GetInitialStartX() ) * pti.get_d(); double dl1p1y = dms.GetInitialStartY() + (dms.GetFinalStartY() - dms.GetInitialStartY() ) * pti.get_d(); double dl1p2x = dms.GetInitialEndX() + (dms.GetFinalEndX() - dms.GetInitialEndX() ) * pti.get_d(); double dl1p2y = dms.GetInitialEndY() + (dms.GetFinalEndY() - dms.GetInitialEndY() ) * pti.get_d(); double dl2p1x = dms.GetInitialStartX() + (dms.GetFinalStartX() - dms.GetInitialStartX() ) * ptf.get_d(); double dl2p1y = dms.GetInitialStartY() + (dms.GetFinalStartY() - dms.GetInitialStartY() ) * ptf.get_d(); double dl2p2x = dms.GetInitialEndX() + (dms.GetFinalEndX() - dms.GetInitialEndX() ) * ptf.get_d(); double dl2p2y = dms.GetInitialEndY() + (dms.GetFinalEndY() - dms.GetInitialEndY() )*ptf.get_d(); if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() gridtrapezium " << i << ": (" << dl1p1x << " " << dl1p1y << " " << dl1p2x << " " << dl1p2y << ")-(" << dl2p1x << " " << dl2p1y << " " << dl2p2x << " " << dl2p2y << ")" << endl; double dMinX, dMaxX, dMinY, dMaxY; minmax4(dl1p1x, dl1p2x, dl2p1x, dl2p2x, dMinX, dMaxX); minmax4(dl1p1y, dl1p2y, dl2p1y, dl2p2y, dMinY, dMaxY); dMaxX += 1.; dMaxY += 1.; dMinX *= sFac.get_d(); dMaxX *= sFac.get_d(); dMinY *= sFac.get_d(); dMaxY *= sFac.get_d(); if ( (dMaxX < lMinX) ||(lMaxX < dMinX) ||(dMaxY < lMinY) ||(lMaxY < dMinY) ) { continue; } PreciseMSegmentData pdms; preciseSegments->Get(segmentsStartPos+i, &pdms); mpq_class l1p1x = dms.GetInitialStartX() + pdms.GetInitialStartX(preciseCoordinates) + (dms.GetFinalStartX() + pdms.GetFinalStartX(preciseCoordinates) - (dms.GetInitialStartX() + pdms.GetInitialStartX(preciseCoordinates)))*pti; mpq_class l1p1y = dms.GetInitialStartY() + pdms.GetInitialStartY(preciseCoordinates) + (dms.GetFinalStartY() + pdms.GetFinalStartY(preciseCoordinates) - (dms.GetInitialStartY() + pdms.GetInitialStartY(preciseCoordinates)))*pti; mpq_class l1p2x = dms.GetInitialEndX() + pdms.GetInitialEndX(preciseCoordinates) + (dms.GetFinalEndX() + pdms.GetFinalEndX(preciseCoordinates) - (dms.GetInitialEndX() + pdms.GetInitialEndX(preciseCoordinates)))*pti; mpq_class l1p2y = dms.GetInitialEndY() + pdms.GetInitialEndY(preciseCoordinates) + (dms.GetFinalEndY() + pdms.GetFinalEndY(preciseCoordinates) - (dms.GetInitialEndY() + pdms.GetInitialEndY(preciseCoordinates)))*pti; mpq_class l2p1x = dms.GetInitialStartX() + pdms.GetInitialStartX(preciseCoordinates) + (dms.GetFinalStartX() + pdms.GetFinalStartX(preciseCoordinates) - (dms.GetInitialStartX() + pdms.GetInitialStartX(preciseCoordinates)))*ptf; mpq_class l2p1y = dms.GetInitialStartY() + pdms.GetInitialStartY(preciseCoordinates) + (dms.GetFinalStartY() + pdms.GetFinalStartY(preciseCoordinates) - (dms.GetInitialStartY() + pdms.GetInitialStartY(preciseCoordinates)))*ptf; mpq_class l2p2x = dms.GetInitialEndX() + pdms.GetInitialEndX(preciseCoordinates) + (dms.GetFinalEndX() + pdms.GetFinalEndX(preciseCoordinates) - (dms.GetInitialEndX() + pdms.GetInitialEndX(preciseCoordinates)))*ptf; mpq_class l2p2y = dms.GetInitialEndY() + pdms.GetInitialEndY(preciseCoordinates) + (dms.GetFinalEndY() + pdms.GetFinalEndY(preciseCoordinates) - (dms.GetInitialEndY() + pdms.GetInitialEndY(preciseCoordinates)))*ptf; l1p1x = l1p1x * sFac; l1p1x.canonicalize(); l1p1y = l1p1y * sFac; l1p1y.canonicalize(); l1p2x = l1p2x * sFac; l1p2x.canonicalize(); l1p2y = l1p2y * sFac; l1p2y.canonicalize(); l2p1x = l2p1x * sFac; l2p1x.canonicalize(); l2p1y = l2p1y * sFac; l2p1y.canonicalize(); l2p2x = l2p2x * sFac; l2p2x.canonicalize(); l2p2y = l2p2y * sFac; l2p2y.canonicalize(); if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() trapezium " << i << ": (" << l1p1x << " " << l1p1y << " " << l1p2x << " " << l1p2y << ")-(" << l2p1x << " " << l2p1y << " " << l2p2x << " " << l2p2y << ")" << endl; mpq_class tMinX, tMaxX, tMinY, tMaxY; minmax4(l1p1x, l1p2x, l2p1x, l2p2x, tMinX, tMaxX); minmax4(l1p1y, l1p2y, l2p1y, l2p2y, tMinY, tMaxY); if ( (cmp(tMaxX, lMinX) < 0) ||(cmp(lMaxX, tMinX) < 0) ||(cmp(tMaxY, lMinY) < 0) ||(cmp(lMaxY, tMinY) < 0)) { continue; } int pos1 = pointPositionToSegment(p1x, p1y, l1p1x, l1p1y, l1p2x, l1p2y); if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() Startposition: " << pos1 << endl; int pos2 = pointPositionToSegment(p2x, p2y, l2p1x, l2p1y, l2p2x, l2p2y); if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() Endposition : " << pos2 << endl; if (iv.start == iv.end) // simple planar case { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() planar" << endl; if (pos1 == 0) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() point " << "is on segment" << endl; TrapeziumSegmentIntersection2 tsi; tsi.x = mpq_class(p1x); tsi.y = mpq_class(p1y); tsi.t = iv.start; tsi.type=TSI_ENTER; vtsi.push_back(tsi); tsi.type=TSI_LEAVE; vtsi.push_back(tsi); } continue; } if (pos1 == 0 && pos2 == 0) // start and end point on start and end line of trapezium { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() start/" << "end point is on start/end segment" << endl; TrapeziumSegmentIntersection2 tsi; tsi.x = mpq_class(p1x); tsi.y = mpq_class(p1y); tsi.t = iv.start; tsi.type=TSI_ENTER; vtsi.push_back(tsi); tsi.x = mpq_class(p2x); tsi.y = mpq_class(p2y); tsi.t = iv.end; tsi.type=TSI_LEAVE; vtsi.push_back(tsi); continue; } if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() try to " << "find intersections..." << endl; mpq_class ax = l2p1x - l1p1x + p1x - p2x; mpq_class ay = l2p1y - l1p1y + p1y - p2y; mpq_class bx = l1p2x - l1p1x; mpq_class by = l1p2y - l1p1y; mpq_class cx = l2p2x + l1p1x - l2p1x - l1p2x; mpq_class cy = l2p2y + l1p1y - l2p1y - l1p2y; mpq_class dx = p1x - l1p1x; mpq_class dy = p1y - l1p1y; mpq_class ab = ax*by - bx*ay; mpq_class cb = cx*by - bx*cy; mpq_class da = dx*ay - ax*dy; mpq_class dc = dx*cy - cx*dy; mpq_class t1(-1); mpq_class t2(-1); bool p1found = false; bool p2found = false; if (cmp((dc + ab), 0) != 0) // linear case maximum one intersection { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() linear case" << endl; t1 = -da / (dc + ab); } else if (cmp(dc, 0) == 0 && cmp(ab, 0) == 0 && cmp(da, 0) == 0) // point movement is inside trapezium plane { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() point " << "moves inside segment case" << endl; t1 = mpq_class(0); t2 = mpq_class(1); } if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() found t1 = " << t1 << " and t2 = " << t2 << endl; if ((cmp(t1, 0) < 0 || cmp(t1, 1) > 0) && (cmp(t2, 0) < 0 || cmp(t2, 1) > 0)) continue; mpq_class s1(-1); mpq_class s2(-1); if (!(cmp(t1, 0) < 0 || cmp(t1, 1) > 0)) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() handle t1..." << endl; mpq_class s11 = ax + cx * t1; mpq_class s12 = ay + cy * t1; if (cmp(s11, 0) != 0) { s11 = (dx - bx * t1) / s11; if (!(cmp(s11, 0) < 0 || cmp(s11, 1) > 0)) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() t1 is a " << "valid case" << endl; s1 = s11; p1found = true; } } else if (cmp(s12, 0) != 0) { s12 = (dy - by * t1) / s12; if (!(cmp(s12, 0) < 0 || cmp(s12, 1) > 0)) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() t1 is a " << "valid case" << endl; s1 = s12; p1found = true; } } } // set order to s1 < s2 if two intersection points exists // set only s1 if just one intersection point exists if (!(cmp(t2, 0) < 0 || cmp(t2, 1) > 0)) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() handle t2..." << endl; mpq_class s21 = ax + cx * t2; mpq_class s22 = ay + cy * t2; if (cmp(s21, 0) != 0) { s21 = (dx - bx * t2) / s21; if (!(cmp(s21, 0) < 0 || cmp(s21, 1) > 0)) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() t2 is a " << "valid case" << endl; s2 = s21; p2found = true; } } else if (cmp(s22, 0) != 0) { s22 = (dy - by * t2) / s22; if (!(cmp(s22, 0) < 0 || cmp(s22, 1) > 0)) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() t2 is a " << "valid case" << endl; s2 = s22; p2found = true; } } if (p2found) { if (!p1found) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() set t2 " << "to first solution, because t1 is not valid" << endl; s1 = s2; p1found = true; p2found = false; } else if (cmp(s1, s2) > 0) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() change " << "t1 and t2 because of order" << endl; s21 = s2; s2 = s1; s1 = s21; mpq_class h = t1; t1 = t2; t2 = h; } } } if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() solution " << "found: " << p1found << " " << p2found << endl; if (!p1found && !p2found) continue; if (p1found) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() solution 1: " << "s = " << s1 << " t = " << t1 << endl; TrapeziumSegmentIntersection2 tsi1; tsi1.x = l1p1x + s1 * (l2p1x - l1p1x) + t1 * (l1p2x - l1p1x + s1 * (l2p2x + l1p1x - l1p2x - l2p1x)); tsi1.y = l1p1y + s1 * (l2p1y - l1p1y) + t1 * (l1p2y - l1p1y + s1 * (l2p2y + l1p1y - l1p2y - l2p1y)); tsi1.t = iv.start + s1 * (iv.end - iv.start); if (pos1 > 0) { if ( (pos1 < 4) == dms.GetInsideAbove() ) tsi1.type=TSI_LEAVE; else tsi1.type=TSI_ENTER; } else { if ( (pos2 < 4) == dms.GetInsideAbove() ) tsi1.type=TSI_ENTER; else tsi1.type=TSI_LEAVE; } if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() solution 1: (" << tsi1.x << " " << tsi1.y << ") t = " << tsi1.t << " mit Typ " << tsi1.type << endl; vtsi.push_back(tsi1); if (p2found) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() solution 2: " << "s = " << s2 << " t = " << t2 << endl; TrapeziumSegmentIntersection2 tsi2; tsi2.x = l1p1x + s2 * (l2p1x - l1p1x) + t2 * (l1p2x - l1p1x + s2 * (l2p2x + l1p1x - l1p2x - l2p1x)); tsi2.y = l1p1y + s2 * (l2p1y - l1p1y) + t2 * (l1p2y - l1p1y + s2 * (l2p2y + l1p1y - l1p2y - l2p1y)); tsi2.t = iv.start + s2 * (iv.end - iv.start); if (tsi1.type == TSI_ENTER) tsi2.type=TSI_LEAVE; else tsi2.type=TSI_ENTER; if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionFind() solution " << "2: (" << tsi2.x << " " << tsi2.y << ") t = " << tsi2.t << " mit Typ " << tsi2.type << endl; vtsi.push_back(tsi2); } } } } /* 1.1.1 Method ~RestrictedIntersectionFix()~ */ bool URegionEmb2::RestrictedIntersectionFix( vector& vtsi) const { /* Examines intersections with same coordinate, counts $TSI\_LEAVE$ and $TSI\_ENTER$ intersections and results in one or zero intersections with the same coordinate, based on whether there are more $TSI\_LEAVE$ or $TSI\_ENTER$ intersections or the same number of them. */ TsiType lastType = TSI_IGNORE; if (MR2_DEBUG) for (unsigned int i = 0; i < vtsi.size(); i++) cerr << "URegionEmb2::RIFix() intersection dump #" << i << " type=" << vtsi[i].type << " ip=[" << vtsi[i].x << " " << vtsi[i].y << " " << vtsi[i].t << "]" << endl; unsigned int fixpos = vtsi.size(); for (unsigned int i = 0; i < vtsi.size(); i++) { if (MR2_DEBUG) cerr << "URegionEmb2::RIFix() post-sort i=" << i << endl; unsigned int j; unsigned int numEnter = 0; unsigned int numLeave = 0; mpq_class t = vtsi[i].t; mpq_class x = vtsi[i].x; mpq_class y = vtsi[i].y; for (j = i; j < vtsi.size() && cmp(vtsi[j].t, t) == 0 && cmp(vtsi[j].x, x) == 0 && cmp(vtsi[j].y, y) == 0; j++) { if (vtsi[j].type == TSI_ENTER) numEnter++; else numLeave++; } j--; if (MR2_DEBUG) { cerr << "URegionEmb2::RIFix() post-sort j=" << j << endl; cerr << "URegionEmb2::RIFix() post-sort numEnter=" << numEnter << endl; cerr << "URegionEmb2::RIFix() post-sort numLeave=" << numLeave << endl; } if (j > i) { if (numEnter == numLeave) { if (i > 0 && lastType == TSI_ENTER) { vtsi[i].type = TSI_LEAVE; vtsi[i+1].type = TSI_ENTER; lastType = TSI_ENTER; } else { vtsi[i].type = TSI_ENTER; vtsi[i+1].type = TSI_LEAVE; lastType = TSI_LEAVE; } for (unsigned int k = i+2; k <= j; k++) vtsi[k].type = TSI_IGNORE; } else if (numEnter > numLeave) { vtsi[i].type = TSI_ENTER; for (unsigned int k = i+1; k <= j; k++) vtsi[k].type = TSI_IGNORE; lastType = TSI_ENTER; if (fixpos > i) fixpos = i; } else { vtsi[i].type = TSI_LEAVE; for (unsigned int k = i+1; k <= j; k++) vtsi[k].type = TSI_IGNORE; lastType = TSI_LEAVE; if (fixpos > i) fixpos = i; } i = j; } else { lastType = vtsi[i].type; if (fixpos > i) fixpos = i; } } unsigned int pos = 0; for (unsigned int i = 1; i < vtsi.size(); i++) { if (MR2_DEBUG) cerr << "URegionEmb2::RIFix() intersection dump #" << i << " type=" << vtsi[i].type << " ip=[" << vtsi[i].x << " " << vtsi[i].y << " " << vtsi[i].t << "] pos=" << pos << endl; if (vtsi[i].type == TSI_ENTER || vtsi[i].type == TSI_LEAVE) { if (MR2_DEBUG) cerr << "URegionEmb2::RIFix() keeping" << endl; pos++; if (pos < i) vtsi[pos] = vtsi[i]; if (fixpos == i) fixpos = pos; } } unsigned int last = vtsi.size(); for (unsigned int i = pos+1; i < last; i++) vtsi.pop_back(); if (fixpos < vtsi.size()) for (unsigned int i = fixpos; i > 1; i--) { if (vtsi[i].type == vtsi[i-1].type && vtsi[i-1].t == vtsi[i-2].t) { vtsi[i-1].type = vtsi[i-2].type; vtsi[i-2].type = vtsi[i].type; } } for (unsigned int i = 1; i < vtsi.size(); i++) assert(vtsi[i].type != vtsi[i-1].type); return (fixpos < vtsi.size()); } /* 1.1.1 Method ~RestrictedIntersectionProcess()~ */ bool URegionEmb2::RestrictedIntersectionProcess(const UPoint& up, const precTimeInterval& iv, vector& vtsi, vector& vpup, vector& vpub, bool isbool) const { if (MR2_DEBUG) cerr << "URegionEmb2::RIP() called, interval=" << iv.start << " " << iv.end << " " << iv.lc << " " << iv.rc << endl; if (vtsi.size() == 0) return false; precUPoint pup; precUBool pub; int prev_i = -1; bool prev_c = false; for (unsigned int i = 0; i < vtsi.size(); i++) { if (MR2_DEBUG) cerr << "URegionEmb2::RIP() intersection dump #" << i << " type=" << vtsi[i].type << " ip=[" << vtsi[i].x << " " << vtsi[i].y << " " << vtsi[i].t << "]" << endl; if (isbool && i == 0 && vtsi[i].type == TSI_ENTER && cmp(iv.start, vtsi[i].t) != 0) { if (MR2_DEBUG) cerr << "URegionEmb2::RIP() special case ENTER (start)" << endl; bool rc = (cmp(vtsi[i].t, iv.end) == 0) ? !iv.rc : false; pub = precUBool(iv.start, vtsi[i].t, iv.lc, rc, false); vpub.push_back(pub); } if (i == 0 && vtsi[i].type == TSI_LEAVE) { if (MR2_DEBUG) cerr << "URegionEmb2::RIP() special case LEAVE (start)" << endl; bool rc = (cmp(vtsi[i].t, iv.end) == 0) ? iv.rc : true; if (!isbool) { UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); pup = precUPoint(iv.start, vtsi[i].t, iv.lc, rc, rUp.p0.GetX(), rUp.p0.GetY(), vtsi[i].x, vtsi[i].y, up); vpup.push_back(pup); } else { pub = precUBool(iv.start, vtsi[i].t, iv.lc, rc, true); vpub.push_back(pub); } prev_i = i; prev_c = rc; } if (isbool && i > 0 && vtsi[i].type == TSI_ENTER && cmp(vtsi[i-1].t, vtsi[i].t) < 0) { if (MR2_DEBUG) cerr << "URegionEmb2::RIP() normal case ENTER" << endl; bool lc = (prev_i >= 0) ? !prev_c : false; pub = precUBool(vtsi[i-1].t, vtsi[i].t, lc, false, false); vpub.push_back(pub); } if (i > 0 && vtsi[i].type == TSI_LEAVE) { if (MR2_DEBUG) cerr << "URegionEmb2::RIP() normal case LEAVE" << endl; bool lc = (cmp(vtsi[i-1].t, iv.start) == 0) ? iv.lc : true; if (prev_i >= 0 && cmp(vtsi[prev_i].t, vtsi[i-1].t) == 0 && prev_c) lc = false; bool rc = (cmp(vtsi[i].t, iv.end) == 0) ? iv.rc : true; if (!isbool) { pup = precUPoint(vtsi[i-1].t, vtsi[i].t, lc, rc, vtsi[i-1].x, vtsi[i-1].y, vtsi[i].x, vtsi[i].y, up); vpup.push_back(pup); } else { pub = precUBool(vtsi[i-1].t, vtsi[i].t, lc, rc, true); vpub.push_back(pub); } prev_i = i; prev_c = rc; } if (i == vtsi.size()-1 && vtsi[i].type == TSI_ENTER) { if (MR2_DEBUG) cerr << "URegionEmb2::RIP() special case ENTER (end)" << endl; bool lc = (cmp(vtsi[i].t, iv.start) == 0) ? iv.lc : true; if (prev_i >= 0 && cmp(vtsi[prev_i].t, vtsi[i].t) == 0 && prev_c) lc = false; if (!isbool) { UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); pup = precUPoint(vtsi[i].t, iv.end, lc, iv.rc, vtsi[i].x, vtsi[i].y, rUp.p1.GetX(), rUp.p1.GetY(), up); vpup.push_back(pup); } else { pub = precUBool(vtsi[i].t, iv.end, lc, iv.rc, true); vpub.push_back(pub); } prev_i = 0; } if (isbool && i == vtsi.size()-1 && vtsi[i].type == TSI_LEAVE && cmp(vtsi[i].t, iv.end) != 0) { if (MR2_DEBUG) cerr << "URegionEmb2::RIP() special case LEAVE (end)" << endl; bool lc = (cmp(vtsi[i].t, iv.start) == 0) ? !iv.lc : false; pub = precUBool(vtsi[i].t, iv.end, lc, iv.rc, false); vpub.push_back(pub); prev_i = 0; } } return prev_i >= 0; } /* 1.1.1 Method ~RestrictedIntersectionUP()~ Checks whether the point unit ~up~ intersects this region2 unit, while both units are restricted to the interval ~iv~, which must be inside the interval of the two units (this is not checked and must be assured before this method is called!). */ void URegionEmb2::RestrictedIntersectionUP( const DbArray* segments, const DbArray* preciseSegments, const DbArray* preciseCoordinates, const DbArray* preciseInstants, const int scaleFactor, const UPoint& up, const precTimeInterval& iv, vector& vpup, vector& vpub, bool isbool) const { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionUP() called" << endl; vector vtsi; RestrictedIntersectionFind(segments, preciseSegments, preciseCoordinates, preciseInstants, scaleFactor, up, iv, vtsi); if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionUP() vtsi.size()=" << vtsi.size() << endl; if (vtsi.size() > 0) { sort(vtsi.begin(), vtsi.end()); if (!RestrictedIntersectionFix(vtsi)) { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionUP() not fixed!" << endl; unsigned int num = Plumbline(segments, preciseSegments, preciseCoordinates, preciseInstants, scaleFactor, up, iv); if (num > 0 && num % 2 == 1) { for (unsigned int i = 1; i < vtsi.size(); i++) { if (vtsi[i].t == vtsi[i-1].t) { vtsi[i-1].type = TSI_LEAVE; vtsi[i].type = TSI_ENTER; } } } } RestrictedIntersectionProcess(up, iv, vtsi, vpup, vpub, isbool); } else { if (MR2_DEBUG) cerr << "URegionEmb2::RestrictedIntersectionUP() no intersection " << "in whole unit" << endl; unsigned int num = Plumbline(segments, preciseSegments, preciseCoordinates, preciseInstants, scaleFactor, up, iv); if (num > 0 && num % 2 == 1) { if (!isbool) { UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); precUPoint pup; pup = precUPoint(iv.start, iv.end, iv.lc, iv.rc, rUp.p0.GetX(), rUp.p0.GetY(), rUp.p1.GetX(), rUp.p1.GetY(), up); vpup.push_back(pup); } else { precUBool pub; pub = precUBool(iv.start, iv.end, iv.lc, iv.rc, true); vpub.push_back(pub); } } else if (isbool) { precUBool pub; pub = precUBool(iv.start, iv.end, iv.lc, iv.rc, false); vpub.push_back(pub); } } } /* 1 Data type ~uregion2~ 1.1 Class ~URegion2~ 1.1.1 Class definition The class definition has been moved to ~MovingRegion3Algebra.h~. 1.1.1 Constructors */ URegion2::URegion2(unsigned int n) : segments(n), preciseSegments(n), preciseCoordinates(0), preciseInstants(0), minIntx(0), minInty(0), maxIntx(0), maxInty(0), minPrecx(0), minPrecy(0), maxPrecx(0), maxPrecy(0) { SetDefined(true); if (MR2_DEBUG) cerr << "URegion2::URegion2() #1 called with " << n << 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; minIntx = 0; minInty = 0; maxIntx = 0; maxInty = 0; minPrecx = mpq_class(0); minPrecy = mpq_class(0); maxPrecx = mpq_class(0); maxPrecy = mpq_class(0); //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 interval(coarseRegion.timeInterval.start, coarseRegion.timeInterval.end, 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; URegionEmb2 uremb(&segments, &preciseSegments, &preciseCoordinates, &preciseInstants, interval, pInt, origUremb, coarseRegion.GetMSegmentData(), 0, scaleFactor); if ( uremb.GetSegmentsNum() == 0 ) { cerr << "Integer Overflow - scale factor " << scaleFactor << " is too big!" << endl; SetDefined(false); return; } SetMinMax(uremb); 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 *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 *lines = newRegion->GetMSegmentData2(); const DbArray *pLines = newRegion->GetPreciseMSegmentData(); const DbArray *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++) { unsigned 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() ? (double)newSeg.GetInitialStartX() : (double)newSeg.GetFinalStartX(), newSeg.GetInitialStartY() < newSeg.GetFinalStartY() ? (double)newSeg.GetInitialStartY() : (double)newSeg.GetFinalStartY(), uremb.timeInterval.start.ToDouble() }; double max[3] = { newSeg.GetInitialStartX() > newSeg.GetFinalStartX() ? (double)newSeg.GetInitialStartX()+1 : (double)newSeg.GetFinalStartX()+1, newSeg.GetInitialStartY() > newSeg.GetFinalStartY() ? (double)newSeg.GetInitialStartY()+1 : (double)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); } /* 1.1.1 Method ~HashValue()~ */ 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()~ for operator 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 ~Translate()~ for operator translate: */ void URegion2::Translate(DateTime* deltaT, double deltaX, double deltaY) { if (MR2_DEBUG) cerr << "URegion2::Translate() called" << endl; uremb.Translate(deltaT, deltaX, deltaY, &segments, &preciseSegments, &preciseCoordinates, scaleFactor); if (uremb.GetSegmentsNum() < 1) SetDefined(false); } /* 1.1.1.1 Method ~Timeshift()~ for operator timeshift: */ void URegion2::Timeshift(DateTime* deltaT) { if (MR2_DEBUG) cerr << "URegion2::Timeshift() called" << endl; uremb.timeInterval.start.Add(deltaT); uremb.timeInterval.end.Add(deltaT); } /* 1.1.1.1 Method ~Scale()~ for operator scale: */ void URegion2::Scale(double deltaX, double deltaY) { if (MR2_DEBUG) cerr << "URegion2::Scale() called" << endl; if (deltaX <= 0 || deltaY <= 0) { cerr << endl << "--------------------------------------------------" << endl << "Scale factors must be greater than zero!" << endl << "--------------------------------------------------" << endl; SetDefined(false); return; } if (checkFactorOverflow(maxIntx, minIntx+1, deltaX)) { cerr << "Overflow of Int values: "; if (deltaX != deltaY) cerr << "x-"; cerr << "Factor " << deltaX << " is too big!" << endl; SetDefined(false); return; } if (checkFactorOverflow(maxInty, minInty+1, deltaY)) { cerr << "Overflow of Int values: y-Factor " << deltaY << " is too big!" << endl; SetDefined(false); return; } uremb.Scale(deltaX, deltaY, &segments, &preciseSegments, &preciseCoordinates); if (uremb.GetSegmentsNum() < 1) SetDefined(false); } /* 1.1.1.1 Method ~TemporalFunction()~ uregion2 at time t */ void URegion2::TemporalFunction(const Instant& t, Region2& 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 ~Initial()~ for operator initial: */ void URegion2::Initial(Instant& t, Region2& res, bool ignoreLimits ) const { if (MR2_DEBUG) cerr << "URegion2::Initial() called" << endl; res.Clear(); if ( !IsDefined() || IsEmpty() ) { res.SetDefined(false); return; } if (!uremb.timeInterval.lc) { res.SetDefined(false); return; } PreciseInterval pi = PreciseInterval(uremb.pInterval); mpq_class pt = mpq_class(pi.GetPreciseInitialInstant(&preciseInstants)); res.SetDefined(true); uremb.TemporalFunction( &segments, &preciseSegments, &preciseCoordinates, &preciseInstants, uremb.timeInterval.start, pt, scaleFactor, res, ignoreLimits); Instant inst(uremb.timeInterval.start.ToDouble()+pt.get_d()); t.CopyFrom(&inst); } /* 1.1.1.1 Method ~Final()~ for operator final: */ void URegion2::Final(Instant& t, Region2& res, bool ignoreLimits ) const { if (MR2_DEBUG) cerr << "URegion2::Final() called" << endl; res.Clear(); if ( !IsDefined() || IsEmpty() ) { res.SetDefined(false); return; } if (!uremb.timeInterval.rc) { res.SetDefined(false); return; } PreciseInterval pi = PreciseInterval(uremb.pInterval); mpq_class pt = mpq_class(pi.GetPreciseFinalInstant(&preciseInstants)); res.SetDefined(true); uremb.TemporalFunction( &segments, &preciseSegments, &preciseCoordinates, &preciseInstants, uremb.timeInterval.end, pt, scaleFactor, res, ignoreLimits); Instant inst(uremb.timeInterval.end.ToDouble()+pt.get_d()); t.CopyFrom(&inst); } /* 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 Region2& val, TemporalUnit& 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(&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 Region2& 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()~ clone function */ 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()~ copy method */ void URegion2::CopyFrom(const Attribute* right) { if (MR2_DEBUG) cerr << "URegion2::CopyFrom() called" << endl; const URegion2* ur = (const URegion2*) right; if( !ur->IsDefined() ){ SetDefined( false ); return; } *this = *ur; this->SetDefined( ur->IsDefined() ); } /* 1.1.1.1 Assignment operator uregion2 assignment */ URegion2& URegion2::operator= ( const URegion2& U) { if (MR2_DEBUG) cerr << "URegion2::operator=() called" << endl; 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; scaleFactor = U.scaleFactor; del.isDefined = U.del.isDefined; uremb = U.uremb; uremb.SetStartPos(0); uremb.pInterval = U.uremb.pInterval; minIntx = U.minIntx; minInty = U.minInty; maxIntx = U.maxIntx; maxInty = U.maxInty; int start = U.uremb.GetStartPos(); int numsegs = U.uremb.GetSegmentsNum(); segments.clean(); for( int i=0 ; 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 for the scalefactor Read and write access to the scaleFactor. The ~SetScaleFactor~ method only sets the scaleFactor, while the ~NewScaleFactor~ method changes the Uregion2-representation, too. */ const int URegion2::GetScaleFactor() { return scaleFactor; } void URegion2::SetScaleFactor(int factor) { scaleFactor = factor; } bool URegion2::NewScaleFactor(int factor) { if (MR2_DEBUG) cerr << "URegion2::NewScaleFactor() called" << endl; if ( scaleFactor != factor) { if (factor > scaleFactor) { int maxInt = max(maxIntx, maxInty); int minInt = min(minIntx, minInty); if (checkFactorOverflow(maxInt, minInt+1, factor-scaleFactor)) return false; } minIntx = 0; minInty = 0; maxIntx = 0; maxInty = 0; minPrecx = 0; minPrecy = 0; maxPrecx = 0; maxPrecy = 0; uremb.NewScale(factor, scaleFactor, &segments, &preciseSegments, &preciseCoordinates); if (uremb.GetSegmentsNum() < 1) return false; scaleFactor = factor; SetMinMax(uremb); } return true; } void URegion2::SetMinMax(URegionEmb2 ur) { maxIntx = ur.maxIntx; maxInty = ur.maxInty; minIntx = ur.minIntx; minInty = ur.minInty; maxPrecx = ur.maxPrecx; maxPrecy = ur.maxPrecy; minPrecx = ur.minPrecx; minPrecy = ur.minPrecy; } /* 1.1.1 In- and Out-Functions 1.1.1.1 Function ~OutURegion2()~ Out function */ 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*) ur->GetFLOB(0), (DbArray*) ur->GetFLOB(1), (DbArray*) ur->GetFLOB(2), (DbArray*) ur->GetFLOB(3), ur->GetScaleFactor()); return nl->TwoElemList(nl->IntAtom(ur->GetScaleFactor()), l); } /* 1.1.1.1 Function ~InURegion2()~ In-Function */ 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 ( )" << endl << "--------------------------------------------------" << endl; return SetWord(Address(0)); } ur->SetScaleFactor(nl->IntValue(nl->First(instance))); URegionEmb2* uremb = InURegionEmbedded2( nl->Second(instance), errorPos, errorInfo, (DbArray*) ur->GetFLOB(0), (DbArray*) ur->GetFLOB(1), (DbArray*) ur->GetFLOB(2), (DbArray*) ur->GetFLOB(3), 0, ur->GetScaleFactor()); 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->SetMinMax(*uremb); 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, "( ( *)),\n" "where represents the scaleFactor,\n" " is ( \n" ") and where is\n" "( ) or an empty list, representing the\n" "initial and final instant.\n" " is ( *),\n" "where and are\n" "( ),\n" "and where is\n" "( ) or an empty list,\n" "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 must be completely within " "corresponding ."); 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 (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 ~MovingRegion3Algebra.h~. 1.1.1 Constructors */ MRegion2::MRegion2(const int n) : Mapping(n), msegmentdata(n), preciseSegmentData(n), preciseCoordinates(0), preciseInstants(0), minIntx(0), minInty(0), maxIntx(0), maxInty(0), minPrecx(0), minPrecy(0), maxPrecx(0), maxPrecy(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(coarseRegion.GetNoComponents()), msegmentdata(0), preciseSegmentData(0), 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; this->scaleFactor = scaleFactor; minIntx = 0; minInty = 0; maxIntx = 0; maxInty = 0; minPrecx = mpq_class(0); minPrecy = mpq_class(0); maxPrecx = mpq_class(0); maxPrecy = mpq_class(0); //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 interval(origUremb.timeInterval.start, origUremb.timeInterval.end, origUremb.timeInterval.lc, origUremb.timeInterval.rc); //initialize precise time interval PreciseInterval pInt(-1); URegionEmb2 uremb(&msegmentdata, &preciseSegmentData, &preciseCoordinates, &preciseInstants, interval, pInt, origUremb, coarseRegion.GetMSegmentData(), msegmentdata.Size(), scaleFactor); if ( uremb.GetSegmentsNum() == 0 ) { cerr << "Integer Overflow - scale factor " << scaleFactor << " is too big!" << endl; SetDefined(false); return; } SetMinMax(uremb); this->Put(i, uremb); } } /* 1.1.1 Private methods 1.1.1.1 Method ~IntersectionMP()~ Main method for the Inside and Intersection procedure. */ void MRegion2::IntersectionMP(const MPoint& mp, MPoint& res1, MBool& res2, bool isbool) { if (MR2_DEBUG) cerr << "MRegion2::IntersectionMP() called" << endl; res1 = MPoint(0); res2 = MBool(0); RefinementPartition2 rp(*this, mp); vector vpup; vector vpub; /* For each interval in the refinement partition, we have to check whether it maps to a region and a point unit. If not, there is obviously no intersection during this interval and we can skip it. Otherwise, we check if the region and point unit, both restricted to this interval, intersect. */ for (unsigned int i = 0; i < rp.Size(); i++) { precTimeInterval iv; int urPos; int upPos; rp.Get(i, iv, urPos, upPos); if (MR2_DEBUG) cerr << "MRegion::IntersectionMP() interval#" << i << ": " << iv.start << " " << iv.end << " " << iv.lc << " " << iv.rc << " " << urPos << " " << upPos << endl; if (upPos == -1) continue; if (urPos == -1) { if (isbool) { precUBool pub = precUBool(iv.start, iv.end, iv.lc, iv.rc, false); vpub.push_back(pub); } continue; } URegionEmb2 ur; UPoint up; Get(urPos, ur); mp.Get(upPos, up); if (MR2_DEBUG) cerr << "MRegion2::IntersectionMP() both elements present" << endl; ur.RestrictedIntersectionUP(&msegmentdata, &preciseSegmentData, &preciseCoordinates, &preciseInstants, scaleFactor, up, iv, vpup, vpub, isbool); } /* Finally the vectors of precise UPoints and precise UBools are converted back to UPoint resp. UBool and added to a MPoint resp. MBool data-type for result. */ if (!isbool) AddUPoints(vpup, res1); else AddUBools(vpub, res2); } /* 1.1.1.1 Method ~AddUPoints()~ Adds all precise UPoint to the MPoint object ~res~ */ void MRegion2::AddUPoints(vector vpup, MPoint& res) const { if (MR2_DEBUG) cerr << "MRegion2::AddUPoints() called" << endl; if (vpup.size() == 0) return; precUPoint last; last = vpup[0]; if (MR2_DEBUG) cerr << "MRegion2::AddUPoints() size of vector: " << vpup.size() << endl; if (MR2_DEBUG) cerr << "0: (" << vpup[0].pti.start << " " << vpup[0].pti.end << " " << vpup[0].pti.lc << " " << vpup[0].pti.rc << ")(" << vpup[0].x0 << " " << vpup[0].y0 << " " << vpup[0].x1 << " " << vpup[0].y1 << ")" << endl; for (unsigned int i = 1; i < vpup.size(); i++) { if (MR2_DEBUG) cerr << i << ": (" << vpup[i].pti.start << " " << vpup[i].pti.end << " " << vpup[i].pti.lc << " " << vpup[i].pti.rc << ")(" << vpup[i].x0 << " " << vpup[i].y0 << " " << vpup[i].x1 << " " << vpup[i].y1 << ")" << endl; if ( (cmp(last.pti.end, vpup[i].pti.start) == 0) && (last.pti.rc || vpup[i].pti.lc) && (last.x1 == vpup[i].x0) && (last.y1 == vpup[i].y0) ) { if (cmp(last.pti.start, last.pti.end) == 0) { last = vpup[i]; last.pti.lc = true; continue; } else if (cmp(vpup[i].pti.start, vpup[i].pti.end) == 0) { last.pti.rc = true; continue; } else { mpq_class f = (last.pti.start - vpup[i].pti.start)/ (vpup[i].pti.end - vpup[i].pti.start); f.canonicalize(); mpq_class x = vpup[i].x0 + (vpup[i].x1 - vpup[i].x0) * f; x.canonicalize(); mpq_class y = vpup[i].y0 + (vpup[i].y1 - vpup[i].y0) * f; y.canonicalize(); if (cmp(last.x0, x) == 0 && cmp(last.y0, y) == 0) { last.pti.end = vpup[i].pti.end; last.pti.rc = vpup[i].pti.rc; last.x1 = vpup[i].x1; last.y1 = vpup[i].y1; continue; } } } UPoint rUp(true); restrictUPointToInterval(last.up, last.pti, rUp); res.Add(rUp); last = vpup[i]; } UPoint rUp(true); restrictUPointToInterval(last.up, last.pti, rUp); res.Add(rUp); } /* 1.1.1.1 Method ~AddUBools()~ Adds all precise UBool to the MBool object ~res~ */ void MRegion2::AddUBools(vector vpub, MBool& res) const { if (MR2_DEBUG) cerr << "MRegion2::AddUBools() called" << endl; if (vpub.size() == 0) return; precUBool last; last = vpub[0]; if (MR2_DEBUG) cerr << "MRegion2::AddUBools() size of vector: " << vpub.size() << endl; if (MR2_DEBUG) cerr << "0: (" << vpub[0].pti.start << " " << vpub[0].pti.end << " " << vpub[0].pti.lc << " " << vpub[0].pti.rc << ") " << vpub[0].status << endl; for (unsigned int i = 1; i < vpub.size(); i++) { if (MR2_DEBUG) cerr << i << ": (" << vpub[i].pti.start << " " << vpub[i].pti.end << " " << vpub[i].pti.lc << " " << vpub[i].pti.rc << ") " << vpub[i].status << endl; if ( (cmp(last.pti.end, vpub[i].pti.start) == 0) && (last.pti.rc || vpub[i].pti.lc) && (last.status == vpub[i].status) ) { if (cmp(last.pti.start, last.pti.end) == 0) { last = vpub[i]; last.pti.lc = true; } else if (cmp(vpub[i].pti.start, vpub[i].pti.end) == 0) { last.pti.rc = true; } else { last.pti.end = vpub[i].pti.end; last.pti.rc = vpub[i].pti.rc; } } else { Instant start(datetime::instanttype); mpq_class reststart(0); precTimeToInstant(last.pti.start, start, reststart); Instant end(datetime::instanttype); mpq_class restend(0); precTimeToInstant(last.pti.end, end, restend); if (last.status && cmp(reststart, 0) > 0) start += Instant(0, 1, datetime::durationtype); if (!last.status && cmp(restend, 0) > 0) end += Instant(0, 1, datetime::durationtype); Interval iv(start, end, last.pti.lc, last.pti.rc); res.Add(UBool(iv, CcBool(true, last.status))); last = vpub[i]; } } Instant start(datetime::instanttype); mpq_class reststart(0); precTimeToInstant(last.pti.start, start, reststart); Instant end(datetime::instanttype); mpq_class restend(0); precTimeToInstant(last.pti.end, end, restend); if (last.status && cmp(reststart, 0) > 0) start += Instant(0, 1, datetime::durationtype); if (!last.status && cmp(restend, 0) > 0) end += Instant(0, 1, datetime::durationtype); Interval iv(start, end, last.pti.lc, last.pti.rc); res.Add(UBool(iv, CcBool(true, last.status))); } /* 1.1.1.1 Method ~SplitHS()~ Split the precise Halfsegments in pHSvector because of the plane sweep */ void MRegion2::SplitHS(vector& pHSvector) { if (MR2_DEBUG) cerr << "MRegion2::SplitHS() called" << endl; int partnerno = 0; for(unsigned int i = 0; i < pHSvector.size()-1; i++ ) for(unsigned int j = i+1; j < pHSvector.size() && pHSvector[j].GetLeftPoint() <= pHSvector[i].GetRightPoint(); j++ ) if ( pHSvector[i] == pHSvector[j] && pHSvector[i].attr.insideAbove == !pHSvector[j].attr.insideAbove) { pHSvector.erase(pHSvector.begin()+j); pHSvector.erase(pHSvector.begin()+i); i--; break; } //split halfsegments, if they cross for(unsigned int i = 0; i < pHSvector.size()-1; i++ ) { for(unsigned int j = i+1; j < pHSvector.size() && pHSvector[j].GetLeftPoint() <= pHSvector[i].GetRightPoint(); j++ ) { Reg2PrecisePoint pp; Reg2PreciseHalfSegment phs; bool newsort = false; if (pHSvector[i].Intersection(pHSvector[j], pp)) { phs = Reg2PreciseHalfSegment(pHSvector[i]); if (pHSvector[i].GetLeftPoint() < pp && pp < pHSvector[i].GetRightPoint()) { pHSvector[i].SetRightPoint(pp); phs.SetLeftPoint(pp); phs.attr.edgeno = partnerno; phs.attr.partnerno = partnerno++; pHSvector.push_back(phs); newsort = true; } phs = Reg2PreciseHalfSegment(pHSvector[j]); if (pHSvector[j].GetLeftPoint() < pp && pp < pHSvector[j].GetRightPoint()) { pHSvector[j].SetRightPoint(pp); phs.SetLeftPoint(pp); phs.attr.edgeno = partnerno; phs.attr.partnerno = partnerno++; pHSvector.push_back(phs); newsort = true; } } else if (pHSvector[i].Contains(pHSvector[j].GetLeftPoint())) { if (pHSvector[i].Contains(pHSvector[j].GetRightPoint())) // pHSvector[j] is inside pHSvector[i] { Reg2PrecisePoint pp1(pHSvector[i].GetLeftPoint()); Reg2PrecisePoint pp2(pHSvector[j].GetLeftPoint()); Reg2PrecisePoint pp3(pHSvector[j].GetRightPoint()); Reg2PrecisePoint pp4(pHSvector[i].GetRightPoint()); phs = Reg2PreciseHalfSegment(pHSvector[i]); if (pp1 < pp2) { pHSvector[i].SetRightPoint(pp2); newsort = true; if (pp3 < pp4) { phs.SetLeftPoint(pp3); phs.attr.edgeno = partnerno; phs.attr.partnerno = partnerno++; pHSvector.push_back(phs); } } else if (pp3 < pp4) { pHSvector[i].SetLeftPoint(pp3); newsort = true; } phs = Reg2PreciseHalfSegment(pHSvector[j]); if (pp1 < pp2 || pp3 < pp4) { phs.attr.insideAbove = pHSvector[i].attr.insideAbove; phs.attr.edgeno = partnerno; phs.attr.partnerno = partnerno++; pHSvector.push_back(phs); newsort = true; } } else if (pHSvector[j].Contains(pHSvector[i].GetRightPoint())) // pHSvector[j] and pHSvector[i] overlaps { Reg2PrecisePoint pp1(pHSvector[i].GetLeftPoint()); Reg2PrecisePoint pp2(pHSvector[j].GetLeftPoint()); Reg2PrecisePoint pp3(pHSvector[i].GetRightPoint()); Reg2PrecisePoint pp4(pHSvector[j].GetRightPoint()); phs = Reg2PreciseHalfSegment(pHSvector[i]); if (pp1 < pp2) pHSvector[i].SetRightPoint(pp2); if (pp3 < pp4) pHSvector[j].SetLeftPoint(pp3); if (pp2 < pp3) { if (pp1 < pp2) { phs.SetLeftPoint(pp2); phs.attr.edgeno = partnerno; phs.attr.partnerno = partnerno++; pHSvector.push_back(phs); } if (pp3 < pp4) { phs.attr.insideAbove = pHSvector[j].attr.insideAbove; phs.attr.edgeno = partnerno; phs.attr.partnerno = partnerno++; pHSvector.push_back(phs); newsort = true; } } } } //sort halfsegments beginning at position j if (newsort) sort(pHSvector.begin()+j, pHSvector.end()); } } sort(pHSvector.begin(), pHSvector.end()); } /* 1.1.1.1 Method ~CollectHS()~ Collects all precise Halfsegements that build a region in the projection to the plane */ void MRegion2::CollectHS(vector& pAllHSvector) { if (MR2_DEBUG) cerr << "MRegion2::CollectHS()" << endl; vector pHSvector; mpz_t sFactor; mpz_init(sFactor); mpq_class sFac(0); uint sfactor; if (scaleFactor < 0) { sfactor = -scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(sFactor), mpz_class(1)); } else { sfactor = scaleFactor; mpz_ui_pow_ui(sFactor, 10, sfactor); sFac = mpq_class(mpz_class(1), mpz_class(sFactor)); } sFac.canonicalize(); mpz_clear(sFactor); //for each region unit, find the halfsegments of it's traversed region // and finally build the union of all these regions for(int i = 0; i < GetNoComponents(); i++) { URegionEmb2 ur; Get(i, ur); pHSvector.clear(); int partnerno = 0; int pos = -1; //first step: collect all halfsegments for (int j = 0; j < ur.GetSegmentsNum(); j++) { MSegmentData2 dms; ur.GetSegment(&msegmentdata, j, dms); PreciseMSegmentData pdms; ur.GetPreciseSegment(&preciseSegmentData, j, pdms); mpq_class pxis = dms.GetInitialStartX() + pdms.GetInitialStartX(&preciseCoordinates); mpq_class pyis = dms.GetInitialStartY() + pdms.GetInitialStartY(&preciseCoordinates); mpq_class pxie = dms.GetInitialEndX() + pdms.GetInitialEndX(&preciseCoordinates); mpq_class pyie = dms.GetInitialEndY() + pdms.GetInitialEndY(&preciseCoordinates); mpq_class pxfs = dms.GetFinalStartX() + pdms.GetFinalStartX(&preciseCoordinates); mpq_class pyfs = dms.GetFinalStartY() + pdms.GetFinalStartY(&preciseCoordinates); mpq_class pxfe = dms.GetFinalEndX() + pdms.GetFinalEndX(&preciseCoordinates); mpq_class pyfe = dms.GetFinalEndY() + pdms.GetFinalEndY(&preciseCoordinates); pxis = pxis * sFac; pyis = pyis * sFac; pxie = pxie * sFac; pyie = pyie * sFac; pxfs = pxfs * sFac; pyfs = pyfs * sFac; pxfe = pxfe * sFac; pyfe = pyfe * sFac; Reg2PrecisePoint is(pxis, pyis); Reg2PrecisePoint ie(pxie, pyie); Reg2PrecisePoint fs(pxfs, pyfs); Reg2PrecisePoint fe(pxfe, pyfe); Reg2PreciseHalfSegment hs; if (is != ie) { hs = Reg2PreciseHalfSegment(true, is, ie); hs.attr.faceno = 0; hs.attr.cycleno = 0; hs.attr.insideAbove = dms.GetInsideAbove(); hs.attr.edgeno = partnerno; hs.attr.partnerno = partnerno++; pHSvector.push_back(hs); pos = pointPositionToSegment(fs, is, ie); if (pos == 2 || pos == 4) { hs.attr.insideAbove = (pos == 2 ? true : false); hs.attr.edgeno = partnerno; hs.attr.partnerno = partnerno++; pHSvector.push_back(hs); } } if (fs != fe) { hs = Reg2PreciseHalfSegment(true, fs, fe); hs.attr.faceno = 0; hs.attr.cycleno = 0; pos = pointPositionToSegment(is, fs, fe); if (pos == 2 || pos == 4) { hs.attr.insideAbove = (pos == 2 ? true : false); hs.attr.edgeno = partnerno; hs.attr.partnerno = partnerno++; pHSvector.push_back(hs); } } if (is != fs) { if (ie != is) pos = pointPositionToSegment(ie, is, fs); else pos = pointPositionToSegment(fe, is, fs); if (pos == 2 || pos == 4) { hs = Reg2PreciseHalfSegment(true, is, fs); hs.attr.faceno = 0; hs.attr.cycleno = 0; hs.attr.insideAbove = (pos == 2 ? true : false); hs.attr.edgeno = partnerno; hs.attr.partnerno = partnerno++; pHSvector.push_back(hs); } } if (ie != fe) { if (is != ie) pos = pointPositionToSegment(is, ie, fe); else pos = pointPositionToSegment(fs, ie, fe); if (pos == 2 || pos == 4) { hs = Reg2PreciseHalfSegment(true, ie, fe); hs.attr.faceno = 0; hs.attr.cycleno = 0; hs.attr.insideAbove = (pos == 2 ? true : false); hs.attr.edgeno = partnerno; hs.attr.partnerno = partnerno++; pHSvector.push_back(hs); } } } sort(pHSvector.begin(), pHSvector.end()); /* The used plane sweep algorithm below is very simple and can't deal with intersecting segments. First of all we have to divide the intersecting segments with crossings or overlappings into their parts. Before starting the plane sweep we have to sort the segments, too. */ SplitHS(pHSvector); // add the corresponding halfsegments for plane sweep unsigned int vs = pHSvector.size(); for(unsigned int k = 0; k < vs; k++ ) { pHSvector[k].attr.edgeno = k; pHSvector[k].attr.partnerno = k; Reg2PreciseHalfSegment hs = pHSvector[k]; hs.SetLeftDomPoint(!hs.IsLeftDomPoint()); pHSvector.push_back(hs); } // 2nd step: sort the set of halfsegments sort(pHSvector.begin(), pHSvector.end()); // 3rd step: plane sweep incl. sort PlaneSweepProjection(pHSvector); // 4th step: merge halfsegments MergeHS(pHSvector); // collect the resulting set of halfsegments in the result set for(unsigned int k = 0; k < pHSvector.size(); k++ ) pAllHSvector.push_back(pHSvector[k]); } if (GetNoComponents() < 2) return; sort(pAllHSvector.begin(), pAllHSvector.end()); SplitHS(pAllHSvector); // add the corresponding halfsegments unsigned int vs = pAllHSvector.size(); for(unsigned int i = 0; i < vs; i++ ) { pAllHSvector[i].attr.edgeno = i; pAllHSvector[i].attr.partnerno = i; Reg2PreciseHalfSegment hs = pAllHSvector[i]; hs.SetLeftDomPoint(!hs.IsLeftDomPoint()); pAllHSvector.push_back(hs); } } /* The following class ~slattr~ is a helper class for the plane sweep algorithm to handle the status ~nabove~ of the segment with in dex ~HSindex~. */ class slattr { public: int HSindex; int nabove; inline slattr() { HSindex = -1; nabove = -1; }; inline slattr(int hsi, int n = -1) : HSindex(hsi), nabove(n) {}; }; /* 1.1.1.1 Method ~aboveorder()~ The method ~aboveorder~ is true, if segment s2 is above s1, otherwise it is false. This order is used in the plane sweep algorithm. */ bool aboveorder(const Reg2PreciseHalfSegment& s1, const Reg2PreciseHalfSegment& s2) // s2 is above s1, order is s1 < s2 { mpq_class x = s2.GetLeftPoint().x > s1.GetLeftPoint().x ? s2.GetLeftPoint().x : s1.GetLeftPoint().x; x.canonicalize(); mpq_class s1y; if (cmp(s1.GetRightPoint().x, s1.GetLeftPoint().x) != 0) s1y = (x - s1.GetLeftPoint().x)*(s1.GetRightPoint().y - s1.GetLeftPoint().y)/(s1.GetRightPoint().x - s1.GetLeftPoint().x) + s1.GetLeftPoint().y; else s1y = s1.GetLeftPoint().y; s1y.canonicalize(); mpq_class s2y; if (cmp(s2.GetRightPoint().x, s2.GetLeftPoint().x) != 0) s2y = (x - s2.GetLeftPoint().x)*(s2.GetRightPoint().y - s2.GetLeftPoint().y)/(s2.GetRightPoint().x - s2.GetLeftPoint().x) + s2.GetLeftPoint().y; else s2y = s2.GetLeftPoint().y; s2y.canonicalize(); if (cmp(s1y, s2y) == 0) { x = s1.GetRightPoint().x < s2.GetRightPoint().x ? s1.GetRightPoint().x : s2.GetRightPoint().x; x.canonicalize(); if (cmp(s1.GetRightPoint().x, s1.GetLeftPoint().x) != 0) s1y = (x - s1.GetLeftPoint().x)*(s1.GetRightPoint().y - s1.GetLeftPoint().y)/(s1.GetRightPoint().x - s1.GetLeftPoint().x) + s1.GetLeftPoint().y; else s1y = s1.GetRightPoint().y; s1y.canonicalize(); if (cmp(s2.GetRightPoint().x, s2.GetLeftPoint().x) != 0) s2y = (x - s2.GetLeftPoint().x)*(s2.GetRightPoint().y - s2.GetLeftPoint().y)/(s2.GetRightPoint().x - s2.GetLeftPoint().x) + s2.GetLeftPoint().y; else s2y = s2.GetRightPoint().y; s2y.canonicalize(); } return (cmp(s1y, s2y) < 0); } /* 1.1.1.1 Method ~PlaneSweepProjection()~ Easy Plane Sweep for unit projections. Precondition: no intersections within all halfsegments */ void MRegion2::PlaneSweepProjection(vector& pHSvector) { if (MR2_DEBUG) cerr << "MRegion2::PlaneSweepProjection() called" << endl; if (MR2_DEBUG) cerr << "MRegion2::PlaneSweepProjection() set partner no.s" << endl; unsigned int vsize = pHSvector.size(); int* TMP = new int[vsize/2]; memset(TMP,0,vsize*sizeof(int) / 2); Reg2PreciseHalfSegment hs; for(unsigned int i = 0; i < vsize; i++ ) { hs = pHSvector[i]; if( hs.IsLeftDomPoint() ) { TMP[hs.attr.edgeno] = i; } else { int p = TMP[hs.attr.edgeno]; pHSvector[i].attr.partnerno = p; pHSvector[p].attr.partnerno = i; } } delete[] TMP; vector sweep; vector regborder; unsigned int j; if (MR2_DEBUG) cerr << "MRegion2::PlaneSweepProjection() execute planesweep" << endl; for(unsigned int i = 0; i < pHSvector.size(); i++ ) { if (!pHSvector[i].IsLeftDomPoint()) { for (j = 0; j < sweep.size(); j++ ) if (sweep[j].HSindex == pHSvector[i].attr.partnerno) { sweep.erase(sweep.begin()+j); break; } } else { slattr inshs(i); for (j = 0; j < sweep.size(); j++ ) if (aboveorder(pHSvector[i], pHSvector[sweep[j].HSindex])) { sweep.insert(sweep.begin()+j, inshs); break; } if (j == sweep.size()) sweep.push_back(inshs); int m, n; if (sweep.size() <= 1 or j <= 0) n = 0; else n = sweep[j-1].nabove; m = n; if (pHSvector[i].attr.insideAbove) n++; else n--; sweep[j].nabove = n; if (m == 0 || n == 0) regborder.push_back(i); } } if (MR2_DEBUG) cerr << "MRegion2::PlaneSweepProjection() delete all non-border " << "elements" << endl; unsigned int borderi = pHSvector.size(); if (!regborder.empty()) { borderi = regborder.back(); regborder.pop_back(); } for(unsigned int i = pHSvector.size(); i > 0; i-- ) { if ((i-1) == borderi) { if (!regborder.empty()) { borderi = regborder.back(); regborder.pop_back(); } else borderi = pHSvector.size(); } else pHSvector.erase(pHSvector.begin()+(i-1)); } } /* 1.1.1.1 Method ~MergeHS()~ The counterpart to the SplitHS method to reconstruct adjacent segments */ void MRegion2::MergeHS(vector& pHSvector) { if (MR2_DEBUG) cerr << "MRegion2::MergeHS() called" << endl; // precondition: pHSvector is sorted by halfsegment order for(unsigned int i = 0; i < pHSvector.size()-1; i++ ) { // only look for concatenating segments if they overlaps! for(unsigned int j = i+1; j < pHSvector.size() && pHSvector[j].GetLeftPoint() <= pHSvector[i].GetRightPoint(); j++ ) { if (pHSvector[i].GetRightPoint() == pHSvector[j].GetLeftPoint()) { bool mergeit = false; mpq_class xi1 = pHSvector[i].GetLeftPoint().x; mpq_class yi1 = pHSvector[i].GetLeftPoint().y; mpq_class xi2 = pHSvector[i].GetRightPoint().x; mpq_class yi2 = pHSvector[i].GetRightPoint().y; mpq_class xj1 = pHSvector[j].GetLeftPoint().x; mpq_class yj1 = pHSvector[j].GetLeftPoint().y; mpq_class xj2 = pHSvector[j].GetRightPoint().x; mpq_class yj2 = pHSvector[j].GetRightPoint().y; if (cmp(xi1, xi2) !=0 ) { mpq_class ki = (yi2 - yi1)/(xi2 - xi1); ki.canonicalize(); if (cmp(xj1, xj2) !=0 ) { mpq_class kj = (yj2 - yj1)/(xj2 - xj1); kj.canonicalize(); if (cmp(ki, kj) == 0) mergeit = true; else continue; } else continue; } else { if (cmp(xj1, xj2) ==0 ) mergeit = true; else continue; } if (mergeit) { if (MR2_DEBUG) cerr << "MRegion2::MergeHS() merge preciseHalfsegment " << i << " with " << j << " (the last one is deleted)" << endl; pHSvector[i].SetRightPoint(pHSvector[j].GetRightPoint()); pHSvector.erase(pHSvector.begin()+j); j--; } } } } } /* 1.1.1.1 Method ~TraverseRegion()~ Main method for traversed. */ void MRegion2::TraverseRegion(Region2& res) { if (MR2_DEBUG) cerr << "MRegion2::TraverseRegion() called" << endl; vector precHSvector; // 1st step: build set of halfsegments CollectHS(precHSvector); if (GetNoComponents() > 1) // the following steps are already handled for each region unit itself // if there is only one unit embedded, we can skip these steps { // 2nd step: sort the set of halfsegments sort(precHSvector.begin(), precHSvector.end()); // 3rd step: plane sweep incl. sort PlaneSweepProjection(precHSvector); // 4th step: merge halfsegments MergeHS(precHSvector); } // 5th step: build the region2 with bulkload mechanism res.StartBulkLoad(); for(unsigned int i = 0; i < precHSvector.size(); i++ ) { precHSvector[i].attr.edgeno = i; precHSvector[i].attr.partnerno = i; res += precHSvector[i]; precHSvector[i].SetLeftDomPoint(!precHSvector[i].IsLeftDomPoint()); res += precHSvector[i]; } res.SetScaleFactor(scaleFactor, false); res.EndBulkLoad(); } /* 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::Get(i, ur); } /* Get read-only access to the DbArrays of this ~MRegion2~ instance */ const DbArray* MRegion2::GetMSegmentData2(void) { return &msegmentdata; } const DbArray* MRegion2::GetPreciseMSegmentData(void) { return &preciseSegmentData; } const DbArray* MRegion2::GetPreciseCoordinates(void) { return &preciseCoordinates; } const DbArray* MRegion2::GetPreciseInstants(void) const { return &preciseInstants; } /* 1.1.1 Access methods for the scalefactor Read and write access to the scaleFactor. The ~SetScaleFactor~ method only sets the scaleFactor, while the ~NewScaleFactor~ method changes the Uregion2-representation, too. */ const int MRegion2::GetScaleFactor(void) { return scaleFactor; } void MRegion2::SetScaleFactor(int factor) { scaleFactor = factor; } bool MRegion2::NewScaleFactor(int factor) { if (MR2_DEBUG) cerr << "MRegion2::NewScaleFactor() called" << endl; if ( scaleFactor != factor) { if (factor > scaleFactor) { int maxInt = max(maxIntx, maxInty); int minInt = min(minIntx, minInty); if (checkFactorOverflow(maxInt, minInt+1, factor-scaleFactor)) return false; } minIntx = 0; minInty = 0; maxIntx = 0; maxInty = 0; minPrecx = 0; minPrecy = 0; maxPrecx = 0; maxPrecy = 0; //for every unit for (int i = 0; i < this->GetNoComponents(); i++) { URegionEmb2 uremb; this->Get(i, uremb); uremb.NewScale(factor, scaleFactor, &msegmentdata, &preciseSegmentData, &preciseCoordinates); if (uremb.GetSegmentsNum() < 1) return false; SetMinMax(uremb); } scaleFactor = factor; } return true; } /* 1.1.1 Methods for database operators 1.1.1.1 Method ~Translate()~ for operator translate: */ void MRegion2::Translate(DateTime* deltaT, double deltaX, double deltaY) { if (MR2_DEBUG) cerr << "MRegion2::Translate() called" << endl; //for every unit for (int i = 0; i < this->GetNoComponents(); i++) { URegionEmb2 uremb; this->Get(i, uremb); uremb.Translate(deltaT, deltaX, deltaY, &msegmentdata, &preciseSegmentData, &preciseCoordinates, scaleFactor); if (uremb.GetSegmentsNum() < 1) { SetDefined(false); return; } this->Put(i, uremb); } } /* 1.1.1.1 Method ~Timeshift()~ for operator timeshift: */ void MRegion2::Timeshift(DateTime* deltaT) { if (MR2_DEBUG) cerr << "MRegion2::Timeshift() called" << endl; //for every unit for (int i = 0; i < this->GetNoComponents(); i++) { URegionEmb2 uremb; this->Get(i, uremb); uremb.timeInterval.start.Add(deltaT); uremb.timeInterval.end.Add(deltaT); this->Put(i, uremb); } } /* 1.1.1.1 Method ~Scale()~ for operator 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; } if (checkFactorOverflow(maxIntx, minIntx+1, deltaX)) { cerr << "Overflow of Int values: "; if (deltaX != deltaY) cerr << "x-"; cerr << "Factor " << deltaX << " is too big!" << endl; SetDefined(false); return; } if (checkFactorOverflow(maxInty, minInty+1, deltaY)) { cerr << "Overflow of Int values: y-Factor " << deltaY << " is too big!" << 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); if (uremb.GetSegmentsNum() < 1) { SetDefined(false); return; } } } /* 1.1.1.1 Method ~AtInstant()~ for operator atinstant: */ void MRegion2::AtInstant(const Instant& t, Intime& 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()~ for operator initial: */ void MRegion2::Initial(Intime& 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); if (cmp(unit.pInterval.GetPreciseInitialInstant(&preciseInstants), 0) > 0) inst += Instant(0, 1, datetime::durationtype); result.instant.CopyFrom(&inst); } /* 1.1.1.1 Method ~Final()~ for operator final: */ void MRegion2::Final(Intime& 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); result.instant.CopyFrom(&inst); } /* 1.1.1.1 Method ~Intersection()~ for operator intersection: */ void MRegion2::Intersection(MPoint& mp, MPoint& res) { if (MR2_DEBUG) cerr << "MRegion2::Intersection() called" << endl; res.Clear(); if( !IsDefined() || !mp.IsDefined() ){ res.SetDefined( false ); return; } res.SetDefined( true ); MBool dummy(0); IntersectionMP(mp, res, dummy); } /* 1.1.1.1 Method ~Inside()~ for operator inside: */ void MRegion2::Inside(const MPoint& mp, MBool& res) { if (MR2_DEBUG) cerr << "MRegion2::Inside() called" << endl; res.Clear(); if( !IsDefined() || !mp.IsDefined() ){ res.SetDefined( false ); return; } res.SetDefined( true ); MPoint dummy(0); IntersectionMP(mp, dummy, res, true); } /* 1.1.1.1 Method ~Traversed()~ for operator traversed: */ void MRegion2::Traversed(Region2& res) { if (MR2_DEBUG) cerr << "MRegion2::Traversed() called" << endl; res.Clear(); if( !IsDefined() ){ res.SetDefined( false ); return; } res.SetDefined( true ); TraverseRegion(res); } void MRegion2::SetMinMax(URegionEmb2 ur) { if (ur.maxIntx > maxIntx) maxIntx = ur.maxIntx; if (ur.maxInty > maxInty) maxInty = ur.maxInty; if (ur.minIntx < minIntx) minIntx = ur.minIntx; if (ur.minInty < minInty) minInty = ur.minInty; if (cmp(ur.maxPrecx, maxPrecx) > 0) maxPrecx = ur.maxPrecx; if (cmp(ur.maxPrecy, maxPrecy) > 0) maxPrecy = ur.maxPrecy; if (cmp(ur.minPrecx, minPrecx) < 0) minPrecx = ur.minPrecx; if (cmp(ur.minPrecy, minPrecy) < 0) minPrecy = ur.minPrecy; } /* 1.1.1 Methods for algebra integration 1.1.1.1 Method ~Clone()~ The clone function: */ 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()~ The copy method: */ 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); SetMinMax(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++) { unsigned 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++) { unsigned 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 Get access to the DbArrays */ int MRegion2::NumOfFLOBs() const { return 5; } Flob* MRegion2::GetFLOB(const int i) { assert(i >= 0 && i <= 4); if (i == 0) { return Mapping::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*) mr->GetFLOB(1), (DbArray*) mr->GetFLOB(2), (DbArray*) mr->GetFLOB(3), (DbArray*) mr->GetFLOB(4), mr->GetScaleFactor()); 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 " << "( (u1 u2 ... un))." << endl << "First element must be atom of IntType and " << "number of elements must be 2." << endl << "--------------------------------------------------" << endl; return SetWord(Address(0)); } mr->SetScaleFactor(nl->IntValue(nl->First(instance))); } else { cerr << endl << "--------------------------------------------------" << endl << "ListExpr is not in correct format ( (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(), mr->GetScaleFactor() ); if (!ur) { correct = false; mr->Destroy(); delete mr; return SetWord(Address(0)); } mr->SetMinMax(*ur); 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, "( (u1 ... un)) with ui uregion2 list representations,\n" "and n >= 1. The value is the scaleFactor for\n" "transformation of coordinates to double. Each ui is of\n" "format ( ), where is\n" "( ) and\n" "where is ( ) or an empty\n" "list, representing precise initial and final instant.\n" "Each in is ( *),\n" "where and are\n" "( ), and where\n" " is ( ) or\n" "an empty list, and the and values representing\n" "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 (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~. */ 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 Operators ~initial~, ~final~, ~atinstant~, ~inst~, ~val~, ~mregiontomregion2~, ~uregiontouregion2~, ~scale~, ~scale2~, ~translate~ 1.1.1 Type mapping functions Used by ~initial~ and ~final~: */ static ListExpr InitialFinalTypeMap(ListExpr args) { if (MR2_DEBUG) cerr << "InitialFinalTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), MRegion2::BasicType())) return nl->SymbolAtom(IRegion2::BasicType()); else if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), URegion2::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 ~inst~: */ static ListExpr IRegion2ToInstantTypeMap(ListExpr args) { if (MR2_DEBUG) cerr << "IRegion2ToInstantTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), IRegion2::BasicType())) return nl->SymbolAtom(Instant::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~val~: */ static ListExpr IRegion2ToRegion2TypeMap(ListExpr args) { if (MR2_DEBUG) cerr << "IRegion2ToRegion2TypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), IRegion2::BasicType())) return nl->SymbolAtom(Region2::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) != 2){ ErrorReporter::ReportError("invalid number of arguments"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (!nl->IsEqual(nl->First(args),MRegion2::BasicType()) && !nl->IsEqual(nl->First(args),URegion2::BasicType())){ ErrorReporter::ReportError( "MRegion2 or URegion2 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->First(args),MRegion2::BasicType())) { if(MR2_DEBUG) cout << "Typemap returns mregion2" << endl; return nl->SymbolAtom(MRegion2::BasicType()); } if (nl->IsEqual(nl->First(args),URegion2::BasicType())) { if(MR2_DEBUG) cout << "Typemap returns uregion2" << endl; return nl->SymbolAtom(URegion2::BasicType()); } return nl->TheEmptyList(); } /* Used by ~scale2~: */ static ListExpr Scale2TypeMap(ListExpr args){ if (MR2_DEBUG) cout << "Scale2TypeMap 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()) && !nl->IsEqual(nl->First(args),URegion2::BasicType())){ ErrorReporter::ReportError( "MRegion2 or URegion2 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 (nl->IsEqual(nl->First(args),MRegion2::BasicType())) { if(MR2_DEBUG) cout << "Typemap returns mregion2" << endl; return nl->SymbolAtom(MRegion2::BasicType()); } if (nl->IsEqual(nl->First(args),URegion2::BasicType())) { if(MR2_DEBUG) cout << "Typemap returns uregion2" << endl; return nl->SymbolAtom(URegion2::BasicType()); } return nl->TheEmptyList(); } /* Used by ~translate~: */ static ListExpr TranslateTypeMap(ListExpr args){ if (MR2_DEBUG) cout << "TranslateTypeMap called " << endl; if (nl->ListLength(args) != 2){ ErrorReporter::ReportError("invalid number of arguments"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (!nl->IsEqual(nl->First(args),MRegion2::BasicType()) && !nl->IsEqual(nl->First(args),URegion2::BasicType())){ ErrorReporter::ReportError( "MRegion2 or URegion2 as first argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (nl->ListLength(nl->Second(args)) == 2) { if (!nl->IsEqual(nl->First(nl->Second(args)),CcReal::BasicType())){ ErrorReporter::ReportError( "double as second argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (!nl->IsEqual(nl->Second(nl->Second(args)),CcReal::BasicType())){ ErrorReporter::ReportError( "double as third argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } else { if (!nl->IsEqual(nl->First(nl->Second(args)),Duration::BasicType())){ ErrorReporter::ReportError( "duration as second argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (!nl->IsEqual(nl->Second(nl->Second(args)),CcReal::BasicType())){ ErrorReporter::ReportError( "double as third argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (!nl->IsEqual(nl->Third(nl->Second(args)),CcReal::BasicType())){ ErrorReporter::ReportError( "double as fourth argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } if (nl->IsEqual(nl->First(args),MRegion2::BasicType())) { if(MR2_DEBUG) cout << "Typemap returns mregion2" << endl; return nl->SymbolAtom(MRegion2::BasicType()); } if (nl->IsEqual(nl->First(args),URegion2::BasicType())) { if(MR2_DEBUG) cout << "Typemap returns uregion2" << endl; return nl->SymbolAtom(URegion2::BasicType()); } return nl->TheEmptyList(); } /* 1.1.1 Selection functions Used by ~deftime~ and ~traversed~: */ 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 ~inst~ and ~val~: */ static int IRegion2Select(ListExpr args) { if (MR2_DEBUG) cerr << "IRegion2Select() called" << endl; if (MR2_DEBUG) cerr << "IRegion2Select() len=" << nl->ListLength(args) << endl; if (MR2_DEBUG) cerr << "IRegio2Select() symbolvalue(first)=" << nl->SymbolValue(nl->First(args)) << endl; if (nl->ListLength(args) == 1 && nl->SymbolValue(nl->First(args)) == IRegion2::BasicType()) return 0; else return -1; } /* Used by ~atinstant~, ~initial~ and ~final~: */ 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; } static int InitialFinalSelect(ListExpr args) { if (MR2_DEBUG) cerr << "AtInstantSelect() called" << endl; if (nl->ListLength(args) == 1 && nl->SymbolValue(nl->First(args)) == MRegion2::BasicType()) return 0; else if (nl->ListLength(args) == 1 && nl->SymbolValue(nl->First(args)) == URegion2::BasicType()) return 1; else return -1; } /* Used by ~scale~, ~scale2~ and ~translate~: */ static int ScaleSelect(ListExpr args) { if (MR2_DEBUG) cerr << "ScaleSelect() called" << endl; if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MRegion2::BasicType() && nl->SymbolValue(nl->Second(args)) == CcReal::BasicType()) return 0; else if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == URegion2::BasicType() && nl->SymbolValue(nl->Second(args)) == CcReal::BasicType()) return 1; else return -1; } static int Scale2Select(ListExpr args) { if (MR2_DEBUG) cerr << "Scale2Select() called" << endl; if (nl->ListLength(args) == 3 && nl->SymbolValue(nl->First(args)) == MRegion2::BasicType() && nl->SymbolValue(nl->Second(args)) == CcReal::BasicType() && nl->SymbolValue(nl->Third(args)) == CcReal::BasicType()) return 0; else if (nl->ListLength(args) == 3 && nl->SymbolValue(nl->First(args)) == URegion2::BasicType() && nl->SymbolValue(nl->Second(args)) == CcReal::BasicType() && nl->SymbolValue(nl->Third(args)) == CcReal::BasicType()) return 1; else return -1; } static int TranslateSelect(ListExpr args) { if (MR2_DEBUG) cerr << "TranslateSelect() called" << endl; if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MRegion2::BasicType()) return 0; else if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == URegion2::BasicType()) return 1; else return -1; } /* 1.1.1 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* res = (Intime*) 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 InitialValueMap_URegion2(Word* args, Word& result, int message, Word& local, Supplier s) { if (MR2_DEBUG) cerr << "InitialValueMap_URegion2() called" << endl; result = qp->ResultStorage(s); Intime* res = (Intime*) result.addr; URegion2* ur = (URegion2*) args[0].addr; Instant* inst = new Instant(); if (ur->IsDefined()) { ur->Initial(*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 FinalValueMap_URegion2(Word* args, Word& result, int message, Word& local, Supplier s) { if (MR2_DEBUG) cerr << "FinalValueMap_URegion2() called" << endl; result = qp->ResultStorage(s); Intime* res = (Intime*) result.addr; URegion2* ur = (URegion2*) args[0].addr; Instant* inst = new Instant(); if (ur->IsDefined()) { ur->Final(*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]); URegion2 res(*ur, factor); ((URegion2*)result.addr)->CopyFrom(&res); return(0); } static int ScaleValueMap_MRegion2(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); MRegion2* mr = (MRegion2*) args[0].addr; CcReal* delta = static_cast(args[1].addr); MRegion2 res(true); res.CopyFrom(*&mr); res.Scale(delta->GetRealval(), delta->GetRealval()); ((MRegion2*)result.addr)->CopyFrom(&res); return (0); } static int ScaleValueMap_URegion2(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); URegion2* ur = (URegion2*) args[0].addr; CcReal* delta = static_cast(args[1].addr); ((URegion2*)result.addr)->CopyFrom(ur); ((URegion2*)result.addr)->Scale(delta->GetRealval(), delta->GetRealval()); return (0); } static int Scale2ValueMap_MRegion2(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); MRegion2* mr = (MRegion2*) args[0].addr; CcReal* deltaX = static_cast(args[1].addr); CcReal* deltaY = static_cast(args[2].addr); MRegion2 res(true); res.CopyFrom(*&mr); res.Scale(deltaX->GetRealval(), deltaY->GetRealval()); ((MRegion2*)result.addr)->CopyFrom(&res); return (0); } static int Scale2ValueMap_URegion2(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); URegion2* ur = (URegion2*) args[0].addr; CcReal* deltaX = static_cast(args[1].addr); CcReal* deltaY = static_cast(args[2].addr); ((URegion2*)result.addr)->CopyFrom(ur); ((URegion2*)result.addr)->Scale(deltaX->GetRealval(), deltaY->GetRealval()); return (0); } static int TranslateValueMap_MRegion2(Word* args, Word& result, int message, Word& local, Supplier s) { if (MR2_DEBUG) cout << "TranslateValueMap called " << endl; result = qp->ResultStorage(s); MRegion2* mr = (MRegion2*) args[0].addr; Word t; Supplier son; DateTime* deltaT; const CcReal* deltaX; const CcReal* deltaY; if (qp->GetNoSons(args[1].addr) == 2) { deltaT = new DateTime (0, 0, datetime::durationtype); son = qp->GetSupplier( args[1].addr, 0 ); qp->Request( son, t ); deltaX = ((CcReal *)t.addr); son = qp->GetSupplier( args[1].addr, 1 ); qp->Request( son, t ); deltaY = ((CcReal *)t.addr); } else { son = qp->GetSupplier( args[1].addr, 0 ); qp->Request( son, t ); deltaT = ((DateTime *)t.addr); son = qp->GetSupplier( args[1].addr, 1 ); qp->Request( son, t ); deltaX = ((CcReal *)t.addr); son = qp->GetSupplier( args[1].addr, 2 ); qp->Request( son, t ); deltaY = ((CcReal *)t.addr); } MRegion2 res(true); res.CopyFrom(*&mr); res.Translate(deltaT, (double)deltaX->GetRealval(), (double)deltaY->GetRealval()); ((MRegion2*)result.addr)->CopyFrom(&res); return (0); } static int TranslateValueMap_URegion2(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); URegion2* ur = (URegion2*) args[0].addr; Word t; Supplier son; DateTime* deltaT; const CcReal* deltaX; const CcReal* deltaY; if (qp->GetNoSons(args[1].addr) == 2) { deltaT = new DateTime (0, 0, datetime::durationtype); son = qp->GetSupplier( args[1].addr, 0 ); qp->Request( son, t ); deltaX = ((CcReal *)t.addr); son = qp->GetSupplier( args[1].addr, 1 ); qp->Request( son, t ); deltaY = ((CcReal *)t.addr); } else { son = qp->GetSupplier( args[1].addr, 0 ); qp->Request( son, t ); deltaT = ((DateTime *)t.addr); son = qp->GetSupplier( args[1].addr, 1 ); qp->Request( son, t ); deltaX = ((CcReal *)t.addr); son = qp->GetSupplier( args[1].addr, 2 ); qp->Request( son, t ); deltaY = ((CcReal *)t.addr); } ((URegion2*)result.addr)->CopyFrom(ur); ((URegion2*)result.addr)->Translate(deltaT, deltaX->GetRealval(), deltaY->GetRealval()); return (0); } /* 1.1.1 Value mapping arrays */ static ValueMapping atinstantvaluemap[] = { MappingAtInstant, AtInstantValueMap_URegion2 }; static ValueMapping initialvaluemap[] = { MappingInitial, InitialValueMap_URegion2 }; static ValueMapping finalvaluemap[] = { MappingFinal, FinalValueMap_URegion2 }; static ValueMapping instvaluemap[] = { IntimeInst }; static ValueMapping valvaluemap[] = { IntimeVal }; static ValueMapping scalevaluemap[] = { ScaleValueMap_MRegion2, ScaleValueMap_URegion2 }; static ValueMapping scale2valuemap[] = { Scale2ValueMap_MRegion2, Scale2ValueMap_URegion2 }; static ValueMapping translatevaluemap[] = { TranslateValueMap_MRegion2, TranslateValueMap_URegion2 }; /* 1.1.1 Operator specifications */ static const string atinstantspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 x instant -> iregion2,\n" "uregion2 x instant -> iregion2" "_ atinstant _ " "Get the iregion2 value of the moving region2 or " "moving region2 unit corresponding to the given instant." "mregion2_1 atinstant instant1 ) )"; static const string initialspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 -> iregion2,\nuregion2 -> iregion2" "initial( _ )" "Get the iregion2 value of the moving region2 or " "moving region2 unit corresponding to the initial instant." "initial( mregion2_1 ) ) )"; static const string finalspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 -> iregion2,\nuregion2 -> iregion2" "final( _ )" "Get the iregion2 value of the moving region2 or " "moving region2 unit corresponding to the final instant." "final( mregion2_1 ) ) )"; static const string instspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( iregion2 -> instant" "inst ( _ )" "iregion time instant." "inst ( ireg2 ) ) )"; static const string valspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( iregion2 -> region2" "val ( _ )" "Intime value." "val ( ireg2 ) ) )"; static const string mregiontomregion2spec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion x int -> mregion2" "mregiontomregion2( _, _)" "Creates a moving region2 from the given moving region" " with a scale of the given int value.\n" "The scalefactor is 10^(scale), this means that " "the integer value is the exponent to the base 10 of " "the new factor.\n" "If the scalefactor is too big resulting in an integer " "overflow, an error is reported." "query mregiontomregion2(mr, sfac)) )"; static const string uregiontouregion2spec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( uregion x int -> uregion2" "uregiontouregion2(_, _)" "Creates a moving region2 unit" " from the given moving region unit" " with a scale of the given int value.\n" "The scalefactor is 10^(scale), this means that " "the integer value is the exponent to the base 10 of " "the new factor.\n" "If the scalefactor is too big resulting in an integer " "overflow, an error is reported." "query uregiontouregion2(ur, sfac)) )"; static const string scalespec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 x real -> mregion2\n" "uregion2 x real -> uregion2" "_ scale [ _ ]" "Changes a given moving region2 or moving region2 " "unit through scaling with the given real value.\n" "If the factor is too big resulting in an integer " "overflow, an error is reported." "query mr2 scale [ delta ]) )"; static const string scale2spec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 x real x real -> mregion2\n" "uregion2 x real x real -> uregion2" "_ scale2 [ _, _ ]" "Changes a given moving region2 or moving region2 " "unit through scaling, using the real values as scale " "factors for x and y.\n" "If the factors are too big resulting in an integer " "overflow, an error is reported." "query mr2 scale2 [ deltax, deltay ]) )"; static const string translatespec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 x duration x real x real -> mregion2\n" "uregion2 x duration x real x real -> uregion2\n" "mregion2 x real x real -> mregion2\n" "uregion2 x real x real -> uregion2" "_ translate [ _, _, _]\n" "_ translate [ _, _]" "Changes a given moving region2 or moving region2 " "unit through moving by a given temporal offset and using " "the real values to move each point parallely in x and y direction.\n" "The duration as temporal offset is an optional parameter.\n" "If the distances are too big resulting in an integer " "overflow, an error is reported." "query mr2 translate [deltat, deltax, deltay]) )"; /* 1.1.1 Operator creation */ static Operator atinstant("atinstant", atinstantspec, 2, atinstantvaluemap, AtInstantSelect, AtInstantTypeMap); static Operator initial("initial", initialspec, 2, initialvaluemap, InitialFinalSelect, InitialFinalTypeMap); static Operator final("final", finalspec, 2, finalvaluemap, InitialFinalSelect, InitialFinalTypeMap); static Operator inst("inst", instspec, 1, instvaluemap, IRegion2Select, IRegion2ToInstantTypeMap); static Operator val("val", valspec, 1, valvaluemap, IRegion2Select, IRegion2ToRegion2TypeMap); static Operator mregiontomregion2("mregiontomregion2", mregiontomregion2spec, MRegionToMRegion2ValueMap, simpleSelect, MRegionToMRegion2TypeMap); static Operator uregiontouregion2("uregiontouregion2", uregiontouregion2spec, URegionToURegion2ValueMap, simpleSelect, URegionToURegion2TypeMap); static Operator scale("scale", scalespec, 2, scalevaluemap, ScaleSelect, ScaleTypeMap); static Operator scale2("scale2", scale2spec, 2, scale2valuemap, Scale2Select, Scale2TypeMap); static Operator mr3translate("translate", translatespec, 2, translatevaluemap, TranslateSelect, TranslateTypeMap); /* 1.1 Operator ~setscalefactor~ */ static ListExpr SetScaleTypeMap(ListExpr args) { if (nl->ListLength(args) != 2){ ErrorReporter::ReportError( "Invalid number of arguments: operator expects 2 arguments"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (!nl->IsEqual(nl->Second(args),CcInt::BasicType())){ ErrorReporter::ReportError( "Type Integer as second argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (nl->IsEqual(nl->First(args),MRegion2::BasicType())){ return nl->SymbolAtom(MRegion2::BasicType()); } else if (nl->IsEqual(nl->First(args),URegion2::BasicType())){ return nl->SymbolAtom(URegion2::BasicType()); } else if (nl->IsEqual(nl->First(args),IRegion2::BasicType())){ return nl->SymbolAtom(IRegion2::BasicType()); } else { ErrorReporter::ReportError( "MRegion2 or URegion2 or IRegion2 as first argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } static int SetScaleSelect(ListExpr args) { if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MRegion2::BasicType()) return 0; else if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == URegion2::BasicType()) return 1; else if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == IRegion2::BasicType()) return 2; else return -1; } static int SetScaleValueMap_MRegion2(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); MRegion2* reg = (MRegion2*) args[0].addr; int newScale = ((CcInt*)args[1].addr)->GetIntval(); MRegion2 reg2(0); reg2.CopyFrom(reg); if (reg2.NewScaleFactor(newScale)) ((MRegion2*)result.addr)->CopyFrom(®2); else { cerr << "Scalefactor " << newScale << " is too big!!" << endl; ((MRegion2*)result.addr)->SetDefined( false ); } return 0; } static int SetScaleValueMap_URegion2(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); URegion2* reg = (URegion2*) args[0].addr; int newScale = ((CcInt*)args[1].addr)->GetIntval(); URegion2 reg2((uint)0); reg2.CopyFrom(reg); if (reg2.NewScaleFactor(newScale)) ((URegion2*)result.addr)->CopyFrom(®2); else { cerr << "Scalefactor " << newScale << " is too big!!" << endl; ((URegion2*)result.addr)->SetDefined( false ); } return 0; } static int SetScaleValueMap_IRegion2(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); IRegion2* reg = (IRegion2*) args[0].addr; int newScale = ((CcInt*)args[1].addr)->GetIntval(); IRegion2 reg2((uint)0); reg2.CopyFrom(reg); if (reg2.value.SetScaleFactor(newScale)) ((IRegion2*)result.addr)->CopyFrom(®2); else { cerr << "Scalefactor " << newScale << " is too big!!" << endl; ((IRegion2*)result.addr)->SetDefined( false ); } return 0; } static ValueMapping SetScaleValueMap[] = { SetScaleValueMap_MRegion2, SetScaleValueMap_URegion2, SetScaleValueMap_IRegion2 }; static const string setscalespec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( mregion2 x int -> mregion2\n" "uregion2 x int -> uregion2\n" "iregion2 x int -> iregion2" "setscalefactor( _, _)" "Changes the scale factor for a given moving region2 " "or moving region2 unit or instant region2.\n" "The new scale factor is 10^(scale), this means that " "the integer value is the exponent to the base 10 of " "the new factor.\n" "If the scalefactor is too big resulting in an integer " "overflow, an error is reported." "query setscalefactor(reg2, 4)) )"; static Operator setscale("setscalefactor", setscalespec, 3, SetScaleValueMap, SetScaleSelect, SetScaleTypeMap); /* 1.1 Operator ~timeshift~ */ ListExpr MR3timeshiftTypeMap( ListExpr args ) { if (nl->ListLength(args) != 2) { ErrorReporter::ReportError( "Invalid number of arguments: operator expects 2 arguments"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (!nl->IsEqual(nl->Second(args),Duration::BasicType())) { ErrorReporter::ReportError( "Duration Type as second argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (nl->IsEqual(nl->First(args),MRegion2::BasicType())) { return nl->SymbolAtom(MRegion2::BasicType()); } else if (nl->IsEqual(nl->First(args),URegion2::BasicType())) { return nl->SymbolAtom(URegion2::BasicType()); } else { ErrorReporter::ReportError( "MRegion2 or URegion2 as first argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } static int MR3timeshiftSelect(ListExpr args) { if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MRegion2::BasicType()) return 0; else if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == URegion2::BasicType()) return 1; else return -1; } int timeshiftValueMap_MRegion2( Word* args, Word& result, int message, Word& local, Supplier s ) { result = qp->ResultStorage(s); MRegion2* reg = (MRegion2*) args[0].addr; DateTime* dt = (DateTime *)args[1].addr; if( reg->IsDefined() && dt->IsDefined() ) { MRegion2 reg2((uint)0); reg2.CopyFrom(reg); reg2.Timeshift(dt); ((MRegion2*)result.addr)->CopyFrom(®2); } else ((MRegion2*)result.addr)->SetDefined( false ); return 0; } int timeshiftValueMap_URegion2( Word* args, Word& result, int message, Word& local, Supplier s ) { result = qp->ResultStorage(s); URegion2* reg = (URegion2*) args[0].addr; DateTime* dt = (DateTime *)args[1].addr; if( reg->IsDefined() && dt->IsDefined() ) { URegion2 reg2((uint)0); reg2.CopyFrom(reg); reg2.Timeshift(dt); ((URegion2*)result.addr)->CopyFrom(®2); } else ((URegion2*)result.addr)->SetDefined( false ); return 0; } static ValueMapping MR3timeshiftValueMap[] = { timeshiftValueMap_MRegion2, timeshiftValueMap_URegion2 }; const string timeshiftspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( mregion2 x duration -> mregion2\n" "uregion2 x duration -> uregion2" "_ timeshift[ _ ]" "Shifts the definition time of the mregion2 or " "uregion2 object." "mr2 timeshift[ create_duration(1, 0) ]" ") )"; Operator mr3timeshift("timeshift", timeshiftspec, 2, MR3timeshiftValueMap, MR3timeshiftSelect, MR3timeshiftTypeMap); /* 1.1 Operator ~intersection~ */ static ListExpr intersectionTypeMap(ListExpr args) { if (MR2_DEBUG) { cerr << "IntersectionTypeMap() 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()); } static int intersectionValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MR2_DEBUG) cerr << "IntersectionValueMap() called" << endl; result = qp->ResultStorage(s); MPoint* res = (MPoint*) result.addr; try { MPoint* mp = (MPoint*) args[0].addr; MRegion2* mr = (MRegion2*) args[1].addr; if (!mp->IsDefined() || !mr->IsDefined()){ res->Clear(); res->SetDefined(false); } else mr->Intersection(*mp, *res); } catch (invalid_argument& e) { cerr << "-----------------------------------------------------------" << endl << "An error occured during the intersection operation:" << endl << e.what() << endl << "-----------------------------------------------------------" << endl; res->SetDefined(false); } return 0; } static const string intersectionspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mpoint x mregion2 -> mpoint" "intersection( _ , _ )" "Intersection between mpoint and mregion2." "query intersection(mpoint1, mregion2) ) )"; static Operator intersection("intersection", intersectionspec, intersectionValueMap, simpleSelect, intersectionTypeMap); /* 1.1 Operator ~inside~ */ static ListExpr insideTypeMap(ListExpr args) { if (MR2_DEBUG) cerr << "InsideTypeMap() 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()); } static int insideValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MR2_DEBUG) cerr << "InsideValueMap() called" << endl; result = qp->ResultStorage(s); MBool* res = (MBool*) result.addr; try { MPoint* mp = (MPoint*) args[0].addr; MRegion2* mr = (MRegion2*) args[1].addr; if (!mp->IsDefined() || !mr->IsDefined()){ res->Clear(); res->SetDefined(false); } else mr->Inside(*mp, *res); } catch (invalid_argument& e) { cerr << "-----------------------------------------------------------" << endl << "An error occured during the inside operation:" << endl << e.what() << endl << "-----------------------------------------------------------" << endl; ((MBool*) result.addr)->SetDefined(false); } return 0; } static const string insidespec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mpoint x mregion2 -> mbool" "_ inside _" "Calculates if and when mpoint is inside " "mregion2." "query mpoint1 inside mregion2 ) )"; static Operator inside("inside", insidespec, insideValueMap, simpleSelect, insideTypeMap); /* 1.1 Operator ~traversed~ */ static ListExpr traversedTypeMap(ListExpr args) { if (MR2_DEBUG) cerr << "TraversedTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), MRegion2::BasicType())) return nl->SymbolAtom(Region2::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } static int traversedValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MR2_DEBUG) cerr << "TraversedValueMap() called" << endl; result = qp->ResultStorage(s); Region2* res = (Region2*) result.addr; MRegion2* mr = (MRegion2*) args[0].addr; if (!mr->IsDefined()) res->SetDefined(false); else mr->Traversed(*res); return 0; } static const string traversedspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 -> region2" "traversed( _ )" "Projection of a moving region2 into the plane." "query traversed(mregion2) ) )"; static Operator traversed("traversed", traversedspec, traversedValueMap, simpleSelect, traversedTypeMap); /* 1.1 Operators ~deftime~ and ~present~ */ static ListExpr deftimeTypeMap(ListExpr args) { if (MR2_DEBUG) cerr << "deftimeTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), MRegion2::BasicType())) return nl->SymbolAtom(Range::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } static ListExpr PresentTypeMap(ListExpr args) { if (MR2_DEBUG) cerr << "PresentTypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MRegion2::BasicType()) && (nl->IsEqual(nl->Second(args), Instant::BasicType()) || nl->IsEqual(nl->Second(args), Range::BasicType()))) return nl->SymbolAtom(CcBool::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } static int deftimeSelect(ListExpr args) { if (MR2_DEBUG) cerr << "deftimeSelect() called" << endl; if (nl->ListLength(args) == 1 && nl->SymbolValue(nl->First(args)) == MRegion2::BasicType()) return 0; else return -1; } static int PresentSelect(ListExpr args) { if (MR2_DEBUG) cerr << "PresentSelect() 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)) == MRegion2::BasicType() && nl->SymbolValue(nl->Second(args)) == Range::BasicType()) return 1; else return -1; } static ValueMapping deftimevaluemap[] = { MappingDefTime }; static ValueMapping presentvaluemap[] = { MappingPresent_i, MappingPresent_p }; static const string deftimespec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 -> periods" " deftime( _ )" " Get the defined time of the mregion2 object." " deftime( mregion1 ) ) )"; static const string presentspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion2 x instant -> bool,\n" "mregion2 x periods -> bool" " _ present _ " " Whether the object is present at the given instant or" " period." " mregion1 present instant1 ) )"; static Operator deftime("deftime", deftimespec, 1, deftimevaluemap, deftimeSelect, deftimeTypeMap); static Operator present("present", presentspec, 2, presentvaluemap, PresentSelect, PresentTypeMap); /* 1 Algebra creation */ class MovingRegion3Algebra : public Algebra { public: MovingRegion3Algebra() : 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(&inst); AddOperator(&val); AddOperator(&mregiontomregion2); AddOperator(&uregiontouregion2); AddOperator(&scale); AddOperator(&scale2); AddOperator(&mr3translate); AddOperator(&mr3timeshift); AddOperator(&deftime); AddOperator(&present); AddOperator(&setscale); AddOperator(&intersection); AddOperator(&inside); AddOperator(&traversed); } ~MovingRegion3Algebra() {} }; } extern "C" Algebra* InitializeMovingRegion3Algebra(NestedList* nlRef, QueryProcessor *qpRef) { nl = nlRef; qp = qpRef; return new temporalalgebra::MovingRegion3Algebra(); }