/* //paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}] //[TOC] [\tableofcontents] //[ue] [\"u] //[ae] [\"a] //[oe] [\"o] \setcounter{tocdepth}{4} [1] The ~MovingRegionAlgebra~ December 2005, initial version created by Holger M[ue]nx for bachelor thesis with Prof. Dr. G[ue]ting, Fachbereich Informatik, Fernuniversit[ae]t Hagen. December 2005, Victor Almeida deleted the deprecated algebra levels (~executable~, ~descriptive~, and ~hibrid~). Only the executable level remains. Models are also removed from type constructors. January-June 2006, various bugfixes and improvements by Holger M[ue]nx, with the help of Victor Almeida and Thomas Behr. November 2006, Christian D[ue]ntgen added operator ~units~. To this end, an additional creator for URegion and assignment operators have been intoduced. [TOC] 1 Introduction The ~MovingRegionAlgebra~ provides datatypes and operators relating to moving regions. To keep the ~TemporalAlgebra~ stable during development, the ~MovingRegionAlgebra~ has been developed as an ~independent~ algebra. Once it is sufficiently stable, it is planned to merge its code into the ~TemporalAlgebra~. Due to the deadline of the bachelor's thesis and the complexity of the ~MovingRegionAlgebra~, the current version should be considered as prototype or proof of concept only, and needs to be finalised before production usage. The class definitions of ~MSegmentData~, ~TrapeziumSegmentIntersection~, ~RefinementPartition~, ~URegion~ and ~MRegion~, which are implemented in ~MovingRegionAlgebra.cpp~, have been moved to the header file ~MovingRegionAlgebra.h~ to facilitate development work on top of the ~MovingRegionAlgebra~ without modifying the ~MovingRegionAlgebra~ itself. This file contains detailed descriptions for the usage of the methods of these classes too. The MovingRegionAlgebra has been developed for the bachelor thesis of Holger M[ue]nx together with Prof. Dr. G[ue]ting, Fachbereich Informatik, Fernuniversit[ae]t Hagen. 1 Known bugs, issues and missing features Open: * Bug: List representation checks incorrect for ~(update mv := ((mregion)((0.0 0.0 true true)(0.0 0.0 1.0 1.0))));~. Aleksej Struk found this issue. Update: Debug output at the beginning on ~InMRegion()~ indicated that this problem actually occurs before ~InMRegion()~ is called. The problem is not caused by the ~MovingRegionAlgebra~. * Feature: Calculations with values of datatype $Instant$ are done with double precision only and not with the datatypes own calculation operations. * Feature: Operator ~traversed~ is not yet implemented. All code which has been prepared for this operator so far is enclosed with ~\#ifdef MRA\_TRAVERSED ... \#endif // MRA\_TRAVERSED~. * Feature: Debug bug output is very verbose. Due to its verbosity, it has impact on the algebra's performance, when enabled. It would be useful to have different debug levels. Closed: * Bug: Lets consider two units ~up~ of type ~upoint~ and ~ur~ of type ~uregion~ with the same interval. If ~val(initial(up))~ is within ~val(initial(ur))~ and ~val(initial(up))~ is not within ~val(final(ur))~, the operators ~intersection~ and ~inside~ correctly recognize the intersection with the edge of the region but do not correctly calculate the intervals when the point is within and outside the region. If ~val(initial(up))~ is within ~val(final(ur))~, everything works. Please note that this bug is causing two failed unit tests. Resolved: Simplifying ~URegion::RestrictedIntersectionFindNormal()~ fixed the issue. * Bug: The ~URegion~ constructor, which constructs the instance from a ~Region~ instance, does not work properly if the region contains half segments, where the two end points have been swapped during half segment created. J[ue]rgen Schmidt spotted this problem. Resolved: Half segments with swapped end points are now being correctly handled. * Bug: There is a number of assertions, which can be triggered by input data. This is caused by rounding errors, which render assumptions verified before inapplicable later. Resolved: Failed asserts replaced by proper error handling. Additionally, some method stubs have been replaced by proper code. If the remaining asserts fail, this will be caused by bugs in the algebra logic or by calls to non-implemented functions or methods, where stubs had to be provided. * Bug: J[oe]rg Schmidt thinks there is an issue in the generation of the refinement partition if two intervals start or end at the same instant. Resolved: Bugfix implemented, storing end instant of previously created interval was incorrect. * Bug: Sorting units at the beginning of RefinementPartition() is missing. Constructor only works if units appear in ~mr~ and ~mp~ in proper order! Rejected: ~InMRegion()~ and ~InMapping()~ sort units by using the ~StartBulkLoad()~ and ~EndBulkLoad()~ methods (the latter with parameter ~true~, of course). * Bug: ~initial~ and ~final~ resulting in failed ~assert()~ when unit's interval is open in the respective instant. Resolved: Added the required checks. * Bug: Objects created in the server version of SECONDO are not compatible with the stand-alone version of SECONDO (and vice versa). Resolved: Replaced weird implementation of ~OpenMRegion()~ and ~SaveMRegion()~ with code based on functions ~Open()~ and ~Save()~ from ~Attribute~. Thomas Behr contributed this valuable hint! * Bug: ~URegion::AddSegment()~ checks for moving segment intersections outside current region unit, which is incorrect. Resolved: Offset ~segmentsStartPos~ in ~URegion::AddSegment()~ was missing. * Bug: Awkward memory leak at the end of ~URegion::TemporalFunction()~. Resolved: Freeing memory now. Resulting code may not be compatible with other compilers than gcc. * Bug: References to ~URegion~ and ~UPoint~ instead of ~Unit1~ and ~Unit2~ in ~RefinementPartition()~. Victor Almeida found this one! Resolved: Replaced references. * Bug: ~iregion~ object creation via ~const iregion value ...~ results in a failed assertion. Resolved: Various modifications outside the MovingRegionAlgebra fixed this without any modifications required for the MovingRegionAlgebra itself. * Bug: Rounding issues have been observed and could be traced back to the value of constant ~eps~ in section \ref{defines}. Resolved: Implemented operator ~mraprec~ which allows to set precision without re-compiling the algreba. * Bug: ~MRegion~ objects cannot be imported into SECONDO according to Thomas Behr. Resolved: Implemented operator ~mraprec~ which allows to set precision without re-compiling the algreba. 1 Unit testing To facilitate automated unit testing, a large number of test cases is provided together with a ~Makefile~ to execute them. These are located in the directory ~Tests~. See the file ~Tests/README~ on running the test cases. Special SECONDO operators have been implemented to make internal functionality of the ~MovingRegionAlgebra~ available for unit testing. These operators are included in the list of test cases below. Please note that you have to compile this algebra with the ~MRA\_UNITTEST~ symbol defined so that the specific unit testing operators are available. Even though this is rendering unit testing slightly more complicated, this approach has been chosen to avoid puzzling users with operators, which are not required for the production version of this algebra. The best place to define this symbol is the ~makefile~, where the proper preparations have been already done at the head of the file. The following groups of test cases are available: * ~Tests/trapeziumintersection.tests~: Checks the functions to calculate the intersection of two trapeziums. These functions are required to check the segments of moving regions for validity. The special operator ~unittest1~ allows unit testing to directly access these functions. * ~Tests/insideabove.tests~: Verifies the ~insideAbove~ attribute of segments in moving regions. The special operator ~unittest2~ provides direct access to the value of this attribute for a specific segment. * ~Tests/refinementpartition.tests~: Assures that the calculation of refinement partitions is correct. The special operator ~unittest3~ provides the refinement partition of two ~mpoint~ values. * ~Tests/basic.tests~: Checks operators ~bbox~, ~inst~, ~val~, ~deftime~ and present. * ~Tests/atinstant.tests~: Checks operators ~atinstant~, ~initial~ and ~final~. * ~Tests/intersection.tests~: Checks operators ~intersection~, ~inside~ and ~at~. * ~Tests/relation.tests~: Checks moving regions as tuple attributes of relations. 1 Defines and includes \label{defines} */ #include #include #include #include "Algebra.h" #include "NestedList.h" #include "QueryProcessor.h" #include "StandardTypes.h" #include "Algebras/Temporal/TemporalAlgebra.h" #include "MovingRegionAlgebra.h" #include "DateTime.h" #include "Symbols.h" extern NestedList* nl; extern QueryProcessor* qp; using namespace std; using namespace datetime; namespace temporalalgebra{ /* Set ~MRA\_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 MRA_DEBUG = false; #define SWITCH_OFF_TRAPEZIUM_INTERSECTS //const bool MRA_DEBUG = true; //#define MRA_TRACE cerr << __PRETTY_FUNCTION__ << " called " << endl; #define MRA_TRACE /* Two floating point numbers are considered equal if their difference is less than the constant ~eps~. Please note that issues have been observed with both too large and too small values of ~eps~. Prof. Dr. G[ue]ting reported an example with incorrect behaviour of operator ~at~ for the value $0.00001$. Thomas Behr reported that correct moving regions have been rejected for value $0.00000001$. The operator ~mraprec~ can be used to set ~eps~, ie. to adjust the precision of double comparisons. Please note that the symbol ~MRA\_PREC~ has to be defined to include this operator in the algebra. The best place to do this is the ~makefile~, and this has been already prepared at the top of the file. A special behaviour has been implemented for the check whether a moving segment is collinear with itself in its initial and ifnal instant (see section \ref{collinear}. Since this check is very prone to rounding errors, the additional constant ~epsRelaxFactor~ has been introduced. During this check, two floating point numbers are considered equal if their difference is less than the constant $eps\cdot\ epsRelaxFactor$. ~epsRelaxFactor~ can be set with the operator ~mraprec~ too. */ //const double eps = 0.0001; //const double eps = 0.00000001; double eps = 0.00001; double epsRelaxFactor = 10; //double epsRelaxFactor = 1000; /* 1 Helper functions 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 ~eps~. 1.1.1 Function ~nearlyEqual()~ Returns ~true~ if $-eps \le a-b \le eps$. */ static bool nearlyEqual(double a, double b) { return abs(a-b) <= eps; } /* 1.1.1 Function ~lowerOrNearlyEqual()~ Returns ~true~ if $a \le b+eps$. */ static bool lowerOrNearlyEqual(double a, double b) { return a < b || nearlyEqual(a, b); } /* 1.1.1 Function ~lower()~ Returns ~true~ if $a < b-eps$. */ static bool lower(double a, double b) { return a < b-eps; } /* 1.1.1 Function ~greaterOrNearlyEqual()~ Returns ~true~ if $a \ge b-eps$. */ static bool greaterOrNearlyEqual(double a, double b) { return a > b || nearlyEqual(a, b); } /* 1.1.1 Function ~between()~ Returns ~true~ if $a-eps \le x \le b+eps$ or $b-eps \le x \le a+eps$. */ static bool between(double a, double x, double b) { return (lowerOrNearlyEqual(a, x) && lowerOrNearlyEqual(x, b)) || (lowerOrNearlyEqual(b, x) && lowerOrNearlyEqual(x, a)); } /* 1.1 Function ~minmax4()~ Returns the minimum and maximum value of $a$, $b$, $c$ and $d$ in $min$ and $max$. */ static void minmax4(double a, double b, double c, double d, double& min, double& max) { if (MRA_DEBUG) cerr << "minmax4() called" << endl; 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; } /* 1 Mathematical and geometrical functions 1.1 Function ~GausTransform()~ 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 transformed matrix and vector are returned in $a$ and $b$. */ static void GaussTransform(const unsigned int n, const unsigned int m, double** a, double* b) { if (MRA_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; } /* 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 (MRA_DEBUG) cerr << "i=" << i << endl; unsigned int j; for (j = i; j < n && a[j][i] == 0; j++) if (MRA_DEBUG) cerr << " failed as pivot: a[" << j << "][" << i << "]=" << 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 (MRA_DEBUG) cerr << " pivot: a[" << j << "][" << i << "]=" << 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) { double 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++) { double f = a[j][i]/a[i][i]; if (MRA_DEBUG) { cerr << " j=" << j << endl; cerr << " f=" << f << endl; } 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; } } if (MRA_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; } } } /* 1.1 Intersections between two segments 1.1.1 Function ~specialSegmentIntersects2()~ Returns ~true~ if the specified segment and line intersect in three-dimensional space $(x, y, t)$. It is not considered as intersection if they touch in their end points. The segment connects the points $(l1p1x, l1p1y, z)$ and $(l1p2x, l1p2y, z)$, ie.\ segment 1 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 specialSegmentIntersects2(double z, double l1p1x, double l1p1y, double l1p2x, double l1p2y, double* P, double* Q) { if (MRA_DEBUG) { cerr << "specialSegmentIntersects2() called" << endl; cerr << "specialSegmentIntersects2() line 1: (" << l1p1x << ", " << l1p1y << ", " << z << ")-(" << l1p2x << ", " << l1p2y << ", " << z << ")" << endl; cerr << "specialSegmentIntersects2() line 2: (" << P[0] << ", " << P[1] << ", " << P[2] << ")-(" << Q[0] << ", " << Q[1] << ", " << Q[2] << ")*t" << endl; } /* 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]; if (MRA_DEBUG) cerr << "specialSegmentIntersects2() t=" << t2 << endl; double x = P[0]+Q[0]*t2; double y = P[1]+Q[1]*t2; if (MRA_DEBUG) cerr << "specialSegmentIntersects2() x=" << x << " y=" << y << endl; double l1MinX = l1p1x < l1p2x ? l1p1x : l1p2x; double l1MaxX = l1p1x > l1p2x ? l1p1x : l1p2x; double l1MinY = l1p1y < l1p2y ? l1p1y : l1p2y; double l1MaxY = l1p1y > l1p2y ? l1p1y : l1p2y; if (MRA_DEBUG) cerr << "specialSegmentIntersects2() l1MinX=" << l1MinX << " l1MaxX=" << l1MaxX << " l1MinY=" << l1MinY << " l1MaxY=" << l1MaxY << endl; if (nearlyEqual(l1p1x, l1p2x) && nearlyEqual(l1p1y, l1p2y)) { /* The segment is actually a point. */ if (MRA_DEBUG) cerr << "specialSegmentIntersects2() " << "no intersection #1" << endl; return false; } else if (nearlyEqual(l1p1x, l1p2x)) { /* The segment is vertical in the $(x, y)$-plane. */ if (nearlyEqual(x, l1p1x) && lower(l1MinY, y) && lower(y, l1MaxY)) { if (MRA_DEBUG) cerr << "specialSegmentIntersects2() " << "intersects #2" << endl; return true; } else { if (MRA_DEBUG) cerr << "specialSegmentIntersects2() " << "no intersection #2" << endl; return false; } } else if (nearlyEqual(l1p1y, l1p2y)) { /* The segment is horizontal in the $(x, y)$-plane. */ if (nearlyEqual(y, l1p1y) && lower(l1MinX, x) && lower(x, l1MaxX)) { if (MRA_DEBUG) cerr << "specialSegmentIntersects2() " << "intersects #3" << endl; return true; } else { if (MRA_DEBUG) cerr << "specialSegmentIntersects2() " << "no intersection #3" << endl; return false; } } else { /* Otherwise, $l1p1x\ne l1p2x$ and $l1p1y\ne l1p2y$ so that we can happily use the quotients below. First, check whether $(x, y)$ is on the line through the segment. */ double t1 = (x-l1p1x)/(l1p2x-l1p1x); if (!nearlyEqual(t1, (y-l1p1y)/(l1p2y-l1p1y))) { if (MRA_DEBUG) cerr << "specialSegmentIntersects2() " << "no intersection #4a" << 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 (lowerOrNearlyEqual(x, l1MinX) || lowerOrNearlyEqual(l1MaxX, x) || lowerOrNearlyEqual(y, l1MinY) || lowerOrNearlyEqual(l1MaxY, y)) { if (MRA_DEBUG) cerr << "specialSegmentIntersects2() " << "no intersection #4b" << endl; return false; } if (MRA_DEBUG) cerr << "specialSegmentIntersects2() " << "intersects" << endl; return true; } } /* 1.1.1 Function ~specialSegmentIntersects1()~ (with $z$) \label{ssi} 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 two lines must meet the following conditions. Segment 1 connects the points $(l1p1x, l1p1y, 0)$ and $(l1p2x, l1p2y, dt)$. Segment 2 connects the points $(l2p1x, l2p1y, 0)$ and $(l2p2x, l2p2y, dt)$. $z$ will contain the $z$-coordinate of the intersection point, if it exists. */ static bool specialSegmentIntersects1(double dt, double l1p1x, double l1p1y, double l1p2x, double l1p2y, double l2p1x, double l2p1y, double l2p2x, double l2p2y, double& z) { if (MRA_DEBUG) { cerr << "specialSegmentIntersects1() w/ z component called" << endl; cerr << "specialSegmentIntersects1() line 1: (" << l1p1x << ", " << l1p1y << ", 0.0)-(" << l1p2x << ", " << l1p2y << ", " << dt << ")" << endl; cerr << "specialSegmentIntersects1() line 2: (" << l2p1x << ", " << l2p1y << ", 0.0)-(" << l2p2x << ", " << l2p2y << ", " << dt << ")" << endl; } /* Check if both segments are identical or touch in their endpoints. */ if (nearlyEqual(l1p1x, l2p1x) && nearlyEqual(l1p1y, l2p1y)) { if (nearlyEqual(l1p2x, l2p2x) && nearlyEqual(l1p2y, l2p2y)) { if (MRA_DEBUG) cerr << "specialSegmentIntersects1() same segment" << endl; return false; } else { if (MRA_DEBUG) cerr << "specialSegmentIntersects1() " << "segments touch in (" << l1p1x << ", " << l1p1y << ")" << endl; return false; } } else if (nearlyEqual(l1p2x, l2p2x) && nearlyEqual(l1p2y, l2p2y)) { if (MRA_DEBUG) cerr << "specialSegmentIntersects1() " << "segments touch in (" << l1p2x << ", " << l1p2y << ")" << endl; return false; } /* The line through segment 1 is $(l1p1x, l1p1y, 0)+(l1p2x-l1p1x, l1p2y-l1p2y, dt)\cdot s$. The line through segment 2 is $(l2p1x, l2p1y, 0)+(l2p2x-l1p1x, l2p2y-l2p2y, dt)\cdot t$. The intersection of the two lines is the solution of the following linear system of equations: \begin{eqnarray} \begin{array}{ccc} \begin{array}{cc} l1p2x-l1p1x & l2p1x-l2p2x \\ l1p2y-l1p1y & l2p1y-l2p2y \\ dt & -dt \end{array} & \left| \begin{array}{c} l2p1x-l1p1x \\ l2p1y-l1p1y \\ 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: */ double A[3][2] = {{ l1p2x-l1p1x, l2p1x-l2p2x }, { l1p2y-l1p1y, l2p1y-l2p2y }, { dt, -dt }}; double B[3] = { l2p1x-l1p1x, l2p1y-l1p1y, 0 }; double* 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 (!nearlyEqual(Ap[i][0], 0.0)) break; /* Row is in format $0 c \left| b \right.$. */ if (nearlyEqual(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. */ if (nearlyEqual(B[i], 0.0)) continue; else { if (MRA_DEBUG) cerr << "specialSegmentIntersects1() " << "do not intersect #1" << endl; return false; } } else { 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. */ if (MRA_DEBUG) cerr << "specialSegmentIntersects1() z=" << z << endl; if (lowerOrNearlyEqual(0.0, z) && lowerOrNearlyEqual(z, dt)) { if (MRA_DEBUG) cerr << "specialSegmentIntersects1() " << "intersect" << endl; return true; } else { if (MRA_DEBUG) cerr << "specialSegmentIntersects1() " << "do not intersect #2" << endl; return false; } } } /* Both segments are located on the same line. We have to check whether they are overlapping. */ if ((between(l1p1x, l2p1x, l1p2x) && between(l1p1y, l2p1y, l1p2y)) || (between(l1p1x, l2p2x, l1p2x) && between(l1p1y, l2p2y, l1p2y)) || (between(l2p1x, l1p1x, l2p2x) && between(l2p1y, l1p1y, l2p2y)) || (between(l2p1x, l1p2x, l2p2x) && between(l2p1y, l1p2y, l2p2y))) return true; else return false; } /* 1.1.1 Function ~specialSegmentIntersects1()~ (without $z$) Same as function in section \ref{ssi}, but not returning the $z$-coordinate of the intersection point. */ static bool specialSegmentIntersects1(double dt, double l1p1x, double l1p1y, double l1p2x, double l1p2y, double l2p1x, double l2p1y, double l2p2x, double l2p2y) { if (MRA_DEBUG) cerr << "specialSegmentIntersects1() w/o z-component called" << endl; double dummy; return specialSegmentIntersects1(dt, l1p1x, l1p1y, l1p2x, l1p2y, l2p1x, l2p1y, l2p2x, l2p2y, dummy); } static int getNearestExpOf2(uint64_t src) { if (src == 0) { return 0; } int exp = 0; while (((uint64_t(1 << exp)) <= src) && (exp < 30)) { exp++; } exp--; if ((exp > 0) && (((1 << (exp - 1)) & src) > 0)) { exp++; } return exp; } static uint64_t getScaleFactor(double dsrc) { uint64_t isrc = (uint64_t)dsrc; if (isrc <= (1 << 30)) { int exp = getNearestExpOf2(isrc); if (exp > 30) { exp = 30; } return (1 << (30 - exp)); } return 1; } /* 1.1 Intersections between two trapeziums 1.1.1 Function ~specialTrapeziumIntersects()~ \label{stinu} Returns ~true~ if and only if the two specified special trapeziums 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. Trapezium 1 is spanned by segments ~(t1p1x, t1p1y, 0)~ to ~(t1p2x, t1p2y, 0)~, ~(t1p1x, t1p1y, 0)~ to ~(t1p3x, t1p3y, dt)~, ~(t1p3x, t1p3y, dt)~ to ~(t1p4x, t1p4x, dt)~ and ~(t1p2x, t1p2y, 0)~ to ~(t1p4x, t1p4x, dt)~. Allowed are either ~(t1p1x, t1p1y, 0)=(t1p2x, t1p2y, 0)~ or ~(t1p3x, t1p3y, dt)=(t1p4x, t1p4x, dt)~ but not both. Segments ~(t1p1x, t1p1y, 0)~ to ~(t1p2x, t1p2y, 0)~ and ~(t1p3x, t1p3y, dt)~ to ~(t1p4x, t1p4x, dt)~ are collinear. Trapezium 2 is spanned by segments ~(t2p1x, t2p1y, 0)~ to ~(t2p2x, t2p2y, 0)~, ~(t2p1x, t2p1y, 0)~ to ~(t2p3x, t2p3y, dt)~, ~(t2p3x, t2p3y, dt)~ to ~(t2p4x, t2p4x, dt)~ and ~(t2p2x, t2p2y, 0)~ to ~(t2p4x, t2p4x, dt)~. Allowed are either ~(t2p1x, t2p1y, 0)=(t2p2x, t2p2y, 0)~ or ~(t2p3x, t2p3y, dt)=(t2p4x, t2p4x, dt)~ but not both. Segments ~(t2p1x, t2p1y, 0)~ to ~(t2p2x, t2p2y, 0)~ and ~(t2p3x, t2p3y, dt)~ to ~(t2p4x, t2p4x, dt)~ are collinear. $dt$ must be greater than $0$. ~detailedResult~ which will contain a numeric representation of the specific case responsible for the return value of the function. (Full description of ~detailedResult~ should be added here.) */ bool specialTrapeziumIntersects( double dt, double t1p1x, double t1p1y, double t1p2x, double t1p2y, double t1p3x, double t1p3y, double t1p4x, double t1p4y, double t2p1x, double t2p1y, double t2p2x, double t2p2y, double t2p3x, double t2p3y, double t2p4x, double t2p4y, unsigned int& detailedResult) { #ifdef SWITCH_OFF_TRAPEZIUM_INTERSECTS return false; #endif if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() " << "(w/ detailedResult) called" << endl; detailedResult = 0; if (MRA_DEBUG) { cerr << "specialTrapeziumIntersects() trapezium 1: (" << t1p1x << ", " << t1p1y << "), (" << t1p2x << ", " << t1p2y << "), (" << t1p3x << ", " << t1p3y << "), (" << t1p4x << ", " << t1p4y << ")" << endl; cerr << "specialTrapeziumIntersects() trapezium 2: (" << t2p1x << ", " << t2p1y << "), (" << t2p2x << ", " << t2p2y << "), (" << t2p3x << ", " << t2p3y << "), (" << t2p4x << ", " << t2p4y << ")" << endl; } /* First, lets check the bounding boxes in the $(x, y)$-plane of the two trapeziums. */ double t1MinX; double t1MaxX; double t1MinY; double t1MaxY; minmax4(t1p1x, t1p2x, t1p3x, t1p4x, t1MinX, t1MaxX); minmax4(t1p1y, t1p2y, t1p3y, t1p4y, t1MinY, t1MaxY); double t2MinX; double t2MaxX; double t2MinY; double t2MaxY; minmax4(t2p1x, t2p2x, t2p3x, t2p4x, t2MinX, t2MaxX); minmax4(t2p1y, t2p2y, t2p3y, t2p4y, t2MinY, t2MaxY); if (MRA_DEBUG) { cerr << "specialTrapeziumIntersects() t1MinX=" << t1MinX << " t1MaxX=" << t1MaxX << " t1MinY=" << t1MinY << " t1MaxY=" << t1MaxY << endl; cerr << "specialTrapeziumIntersects() t2MinX=" << t2MinX << " t2MaxX=" << t2MaxX << " t2MinY=" << t2MinY << " t2MaxY=" << t2MaxY << endl; } // cout << "specialTrapeziumIntersects() trapezium 1: (" << t1p1x << ", " // << t1p1y << "), (" << t1p2x << ", " << t1p2y << "), (" << t1p3x << ", " // << t1p3y << "), (" << t1p4x << ", " << t1p4y << ")" << endl; // cout << "specialTrapeziumIntersects() trapezium 2: (" << t2p1x << ", " // << t2p1y << "), (" << t2p2x << ", " << t2p2y << "), (" << t2p3x << ", " // << t2p3y << "), (" << t2p4x << ", " << t2p4y << ")" << endl; double minX, minY, maxX, maxY; minmax4(t1MinX, t1MaxX, t2MinX, t2MaxX, minX, maxX); minmax4(t1MinY, t1MaxY, t2MinY, t2MaxY, minY, maxY); // cout << "distX = " << maxX - minX << "distY = " << maxY - minY // << "dt = " << dt << endl; uint64_t sx = getScaleFactor(maxX - minX); uint64_t sy = getScaleFactor(maxY - minY); uint64_t st = getScaleFactor(dt); // cout << "sx = " << sx << ", sy = " << sy << ", st = " << st << endl; uint64_t tx = 1 << getNearestExpOf2((maxX + minX) / 2); uint64_t ty = 1 << getNearestExpOf2((maxY + minY) / 2); uint64_t tt = 1 << getNearestExpOf2(dt); t1p1x = (t1p1x - tx) * sx; t1p1y = (t1p1y - ty) * sy; t1p2x = (t1p2x - tx) * sx; t1p2y = (t1p2y - ty) * sy; t1p3x = (t1p3x - tx) * sx; t1p3y = (t1p3y - ty) * sy; t1p4x = (t1p4x - tx) * sx; t1p4y = (t1p4y - ty) * sy; t2p1x = (t2p1x - tx) * sx; t2p1y = (t2p1y - ty) * sy; t2p2x = (t2p2x - tx) * sx; t2p2y = (t2p2y - ty) * sy; t2p3x = (t2p3x - tx) * sx; t2p3y = (t2p3y - ty) * sy; t2p4x = (t2p4x - tx) * sx; t2p4y = (t2p4y - ty) * sy; dt = (dt - tt) * st; // cout << "specialTrapeziumIntersects() trapezium 1: (" << t1p1x << ", " // << t1p1y << "), (" << t1p2x << ", " << t1p2y << "), (" << t1p3x << ", " // << t1p3y << "), (" << t1p4x << ", " << t1p4y << ")" << endl; // cout << "specialTrapeziumIntersects() trapezium 2: (" << t2p1x << ", " // << t2p1y << "), (" << t2p2x << ", " << t2p2y << "), (" << t2p3x << ", " // << t2p3y << "), (" << t2p4x << ", " << t2p4y << ")" << endl; if (lower(t1MaxX, t2MinX) || lower(t2MaxX, t1MinX) || lower(t1MaxY, t2MinY) || lower(t2MaxY, t1MinY)) { if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() no bbox overlap" << endl; detailedResult = 1; return false; } /* Now, lets see if the trapeziums touch in one segment. */ if ((nearlyEqual(t1p1x, t2p1x) && nearlyEqual(t1p1y, t2p1y) && nearlyEqual(t1p3x, t2p3x) && nearlyEqual(t1p3y, t2p3y)) || (nearlyEqual(t1p1x, t2p2x) && nearlyEqual(t1p1y, t2p2y) && nearlyEqual(t1p3x, t2p4x) && nearlyEqual(t1p3y, t2p4y)) || (nearlyEqual(t1p2x, t2p1x) && nearlyEqual(t1p2y, t2p1y) && nearlyEqual(t1p4x, t2p3x) && nearlyEqual(t1p4y, t2p3y)) || (nearlyEqual(t1p2x, t2p2x) && nearlyEqual(t1p2y, t2p2y) && nearlyEqual(t1p4x, t2p4x) && nearlyEqual(t1p4y, t2p4y))) { if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() touching" << endl; detailedResult = 2; return false; } /* The bounding boxes of the trapeziums overlap but they do not touch in one segment. To determine if they actually 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]; double T1B[3]; if (nearlyEqual(t1p1x, t1p2x) && nearlyEqual(t1p1y, t1p2y)) { if (MRA_DEBUG) cerr << "#1a" << endl; T1A[0][0] = t1p4x-t1p3x; T1A[1][0] = t1p4y-t1p3y; T1A[2][0] = 0; T1A[0][1] = t1p1x-t1p3x; T1A[1][1] = t1p1y-t1p3y; T1A[2][1] = -dt; T1B[0] = t1p3x; T1B[1] = t1p3y; T1B[2] = dt; } else { if (MRA_DEBUG) cerr << "#1b" << endl; T1A[0][0] = t1p2x-t1p1x; T1A[1][0] = t1p2y-t1p1y; T1A[2][0] = 0; T1A[0][1] = t1p3x-t1p1x; T1A[1][1] = t1p3y-t1p1y; T1A[2][1] = dt; T1B[0] = t1p1x; T1B[1] = t1p1y; T1B[2] = 0; } double T2A[3][2]; double T2B[3]; if (nearlyEqual(t2p1x, t2p2x) && nearlyEqual(t2p1y, t2p2y)) { if (MRA_DEBUG) cerr << "#2a" << endl; T2A[0][0] = t2p4x-t2p3x; T2A[1][0] = t2p4y-t2p3y; T2A[2][0] = 0; T2A[0][1] = t2p1x-t2p3x; T2A[1][1] = t2p1y-t2p3y; T2A[2][1] = -dt; T2B[0] = t2p3x; T2B[1] = t2p3y; T2B[2] = dt; } else { if (MRA_DEBUG) cerr << "#2b" << endl; T2A[0][0] = t2p2x-t2p1x; T2A[1][0] = t2p2y-t2p1y; T2A[2][0] = 0; T2A[0][1] = t2p3x-t2p1x; T2A[1][1] = t2p3y-t2p1y; T2A[2][1] = dt; T2B[0] = t2p1x; T2B[1] = t2p1y; T2B[2] = 0; } if (MRA_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]); } /* Create a linear system of equations $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]; double B[3]; double* 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 (nearlyEqual(Ap[2][2], 0.0) && nearlyEqual(Ap[2][3], 0.0)) { if (nearlyEqual(B[2], 0.0)) { /* They overlap if one of the segments of each trapezium, which are not parallel to the $(x, y)$-plane, intersect with another of such segments of the other trapezium. */ if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() " << "identical plane" << endl; if (specialSegmentIntersects1( dt, t1p1x, t1p1y, t1p3x, t1p3y, t2p1x, t2p1y, t2p3x, t2p3y) || specialSegmentIntersects1( dt, t1p1x, t1p1y, t1p3x, t1p3y, t2p2x, t2p2y, t2p4x, t2p4y) || specialSegmentIntersects1( dt, t1p2x, t1p2y, t1p4x, t1p4y, t2p1x, t2p1y, t2p3x, t2p3y) || specialSegmentIntersects1( dt, t1p2x, t1p2y, t1p4x, t1p4y, t2p2x, t2p2y, t2p4x, t2p4y)) { if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() intersects" << endl; if (MRA_DEBUG) { cerr << ::std::fixed << ::std::setprecision(6); for (unsigned int i = 0; i < 3; i++) cerr < 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 (lower(ip1ip2MaxX, ip3ip4MinX) || lower(ip3ip4MaxX, ip1ip2MinX) || lower(ip1ip2MaxY, ip3ip4MinY) || lower(ip3ip4MaxY, ip1ip2MinY)) { if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() " << "no intersection" << endl; detailedResult = 10; return false; } else { if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() intersection" << endl; detailedResult = 7; 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 z; double t1zMin = dt; double t1zMax = 0; bool t1Intersects = false; if (specialSegmentIntersects2( 0, t1p1x, t1p1y, t1p2x, t1p2y, P, Q)) { if (MRA_DEBUG) cerr << "#3a" << endl; t1zMin = t1zMin > 0 ? 0 : t1zMin; t1zMax = t1zMax < 0 ? 0 : t1zMax; t1Intersects = true; } if (specialSegmentIntersects2( dt, t1p3x, t1p3y, t1p4x, t1p4y, P, Q)) { if (MRA_DEBUG) cerr << "#3b" << endl; t1zMin = t1zMin > dt ? dt : t1zMin; t1zMax = t1zMax < dt ? dt : t1zMax; t1Intersects = true; } if (specialSegmentIntersects1( dt, t1p1x, t1p1y, t1p3x, t1p3y, P[0], P[1], P[0]+Q[0], P[1]+Q[1], z)) { if (MRA_DEBUG) cerr << "#3c" << endl; t1zMin = t1zMin > z ? z : t1zMin; t1zMax = t1zMax < z ? z : t1zMax; t1Intersects = true; } if (specialSegmentIntersects1( dt, t1p2x, t1p2y, t1p4x, t1p4y, P[0], P[1], P[0]+Q[0], P[1]+Q[1], z)) { if (MRA_DEBUG) cerr << "#3d" << endl; t1zMin = t1zMin > z ? z : t1zMin; t1zMax = t1zMax < z ? z : t1zMax; t1Intersects = true; } double t2zMin = dt; double t2zMax = 0; bool t2Intersects = false; if (specialSegmentIntersects2( 0, t2p1x, t2p1y, t2p2x, t2p2y, P, Q)) { if (MRA_DEBUG) cerr << "#4a" << endl; t2zMin = t2zMin > 0 ? 0 : t2zMin; t2zMax = t2zMax < 0 ? 0 : t2zMax; t2Intersects = true; } if (specialSegmentIntersects2( dt, t2p3x, t2p3y, t2p4x, t2p4y, P, Q)) { if (MRA_DEBUG) cerr << "#4b" << endl; t2zMin = t2zMin > dt ? dt : t2zMin; t2zMax = t2zMax < dt ? dt : t2zMax; t2Intersects = true; } if (specialSegmentIntersects1( dt, t2p1x, t2p1y, t2p3x, t2p3y, P[0], P[1], P[0]+Q[0], P[1]+Q[1], z)) { if (MRA_DEBUG) cerr << "#4c" << endl; t2zMin = t2zMin > z ? z : t2zMin; t2zMax = t2zMax < z ? z : t2zMax; t2Intersects = true; } if (specialSegmentIntersects1( dt, t2p2x, t2p2y, t2p4x, t2p4y, P[0], P[1], P[0]+Q[0], P[1]+Q[1], z)) { if (MRA_DEBUG) cerr << "#4d" << endl; t2zMin = t2zMin > z ? z : t2zMin; t2zMax = t2zMax < z ? z : t2zMax; t2Intersects = true; } if (MRA_DEBUG) { cerr << "specialTrapeziumIntersects() dt=" << dt << endl; cerr << "specialTrapeziumIntersects() t1Intersects=" << t1Intersects << endl; if (t1Intersects) cerr << "specialTrapeziumIntersects() t1zMin=" << t1zMin << " t1zMax=" << t1zMax << endl; cerr << "specialTrapeziumIntersects() t2Intersects=" << t2Intersects << endl; if (t2Intersects) cerr << "specialTrapeziumIntersects() t2zMin=" << t2zMin << " t2zMax=" << t2zMax << endl; } if (t1Intersects && t2Intersects && !(lower(t1zMax, t2zMin) || lower(t2zMax, t1zMin)) && !(nearlyEqual(t1zMax, 0.0) && nearlyEqual(t1zMin, 0.0) && nearlyEqual(t2zMax, 0.0) && nearlyEqual(t2zMin, 0.0)) && !(nearlyEqual(t1zMax, dt) && nearlyEqual(t1zMin, dt) && nearlyEqual(t2zMax, dt) && nearlyEqual(t2zMin, dt))) { if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() intersect" << endl; detailedResult = 8; return true; } else { if (MRA_DEBUG) cerr << "specialTrapeziumIntersects() " << "no intersection" << endl; detailedResult = 9; return false; } } } /* 1.1 Other intersections This section contains functions which examine the intersection between two different object types (such as trapezium and segment). 1.1.1 Function ~specialInsidePointTrapezium()~ Return ~true~ if the point $(x, y, t)$ is within the trapezium spanned by the segments $(l1p1x, l1p1y, t1)$ to $(l1p2x, l1p2y, t1)$ and $(l2p1x, l2p1y, t2)$ to $(l2p2x, l2p2y, t2)$. */ bool specialInsidePointTrapezium(double t, double x, double y, double t1, double l1p1x, double l1p1y, double l1p2x, double l1p2y, double t2, double l2p1x, double l2p1y, double l2p2x, double l2p2y) { if (MRA_DEBUG) cerr << "sIPT() called" << endl; /* Check if $t1 <= t <= t2$ or $t2 <= t < t1$ holds. If not, no intersection can occur. */ if (!(lowerOrNearlyEqual(t1, t) && lowerOrNearlyEqual(t, t2)) && !(lowerOrNearlyEqual(t2, t) && lowerOrNearlyEqual(t, t1))) { if (MRA_DEBUG) cerr << "sIPT() t check failed" << endl; return false; } if (MRA_DEBUG) cerr << "sIPT() t check succeeded" << endl; /* Calculate the points $(x1, y1, t)$ and $(x2, y2, t)$, which are the end points of a segment parallel to $(l1p1x, l1p1y, t1)$ to $(l1p2x, l1p2y, t1)$ and ($l2p1x, l2p1y, t2$ to $(l2p2x, l2p2y, t2)$ and which is located between these two segments. */ double x1; double y1; double x2; double y2; if (nearlyEqual(t1, t2)) { x1 = l1p1x; y1 = l1p1y; x2 = l1p2x; y2 = l1p2y; } else { double f = (t-t1)/(t2-t1); if (MRA_DEBUG) cerr << "sIPT() f=" << f << endl; x1 = l1p1x+(l2p1x-l1p1x)*f; y1 = l1p1y+(l2p1y-l1p1y)*f; x2 = l1p2x+(l2p2x-l1p2x)*f; y2 = l1p2y+(l2p2y-l1p2y)*f; } if (MRA_DEBUG) cerr << "sIPT() x1=" << x1 << " y1=" << y1 << " x2=" << x2 << " y2=" << y2 << endl; /* If $(x, y, t)$ is located on segment $(x1, y1, t)$ and $(x2, y2, t)$, the point is inside the trapezium, and outside otherwise. */ if (((lowerOrNearlyEqual(x1, x) && lowerOrNearlyEqual(x, x2)) || (lowerOrNearlyEqual(x2, x) && lowerOrNearlyEqual(x, x1))) && ((lowerOrNearlyEqual(y1, y) && lowerOrNearlyEqual(y, y2)) || (lowerOrNearlyEqual(y2, y) && lowerOrNearlyEqual(y, y1)))) { if (MRA_DEBUG) cerr << "sIPT() inside" << endl; return true; } else { if (MRA_DEBUG) cerr << "sIPT() not inside" << endl; return false; } } /* 1.1.1 Function ~specialIntersectionTrapeziumSegment()~ Calculates the intersection of a trapezium and a segment in three-dimensional space $(x, y, t)$. The trapezium is spanned by the points ~(l1p1x, l1p1y, t1)~, ~(l1p2x, l1p2y, t1)~, ~(l2p1x, l2p1y, t2)~ and ~(l2p2x, l2p2y, t2)~. ~(l1p1x, l1p1y, t1)=(l1p2x, l1p2y, t1)~ or ~(l2p1x, l2p1y, t2)=(l2p2x, l2p2y, t2)~ is allowed but not both. ~l1t=l2t~ is allowed. The segment is spanned by the points ~(p1x, p1y, t1)~ and ~(p2x, p2y, t2)~. ~(p1x, p1y, t1)=(p2x, p2y, t1)~ is allowed. ~t1=t2~ is allowed. */ void specialIntersectionTrapeziumSegment(double t1, double t2, double l1p1x, double l1p1y, double l1p2x, double l1p2y, double l2p1x, double l2p1y, double l2p2x, double l2p2y, double p1x, double p1y, double p2x, double p2y, bool& ip1present, double& ip1x, double& ip1y, double& ip1t, // sometimes not set! bool& ip2present, double& ip2x, double& ip2y, double& ip2t // sometimes not set! ) { if (MRA_DEBUG) { cerr << "sITS() called" << endl; cerr << "sITS() t1=" << t1 << " t2=" << t2 << " l1=[" << l1p1x << " " << l1p1y << " " << l1p2x << " " << l1p2y << "] l2=[" << l2p1x << " " << l2p1y << " " << l2p2x << " " << l2p2y << "] p=(" << p1x << " " << p1y << " " << p2x << " " << p2y << ")" << endl; } /* Check bounding boxes in $(x, y)$-plane of trapzium and segment. If they do not overlap, trapezium and segment do not intersect. */ double tMinX; double tMaxX; double tMinY; double tMaxY; minmax4(l1p1x, l1p2x, l2p1x, l2p2x, tMinX, tMaxX); minmax4(l1p1y, l1p2y, l2p1y, l2p2y, tMinY, tMaxY); double lMinX = p1x < p2x ? p1x : p2x; double lMaxX = p1x > p2x ? p1x : p2x; double lMinY = p1y < p2y ? p1y : p2y; double lMaxY = p1y > p2y ? p1y : p2y; if (lower(tMaxX, lMinX) || lower(lMaxX, tMinX) || lower(tMaxY, lMinY) || lower(lMaxY, tMinY)) { if (MRA_DEBUG) cerr << "sITS() no bbox overlap" << endl; ip1present = false; ip2present = false; return; } /* Create equations for the plane spanned by the trapezium and the line through the segment. Keep in mind that the trapezium might be a triangle and that the line might be point only. The plane is $P1+P2\cdot (s, t)$, where $T1$ is a vector with three elements and $T2$ a matrix with three rows and two columns, and the line is $L1+L2\cdot u$, where both $L1$ and $L2$ are vectors with three elements. The interesection between plane and line is the solution of the equation $P2\cdot (s, t)-L2\cdot u=L1-T1$. Present the left handed side by the matrix $A$ with three rows and three colums and the right handed side by the verctor $B$ with three elements. */ double A[3][3]; double B[3]; if (nearlyEqual(l1p1x, l1p2x) && nearlyEqual(l1p1y, l1p2y)) { B[0] = -l2p1x; B[1] = -l2p1y; B[2] = -t2; A[0][0] = l2p2x-l2p1x; A[1][0] = l2p2y-l2p1y; A[2][0] = 0; A[0][1] = l1p1x-l2p1x; A[1][1] = l1p1y-l2p1y; A[2][1] = t1-t2; } else { B[0] = -l1p1x; B[1] = -l1p1y; B[2] = -t1; A[0][0] = l1p2x-l1p1x; A[1][0] = l1p2y-l1p1y; A[2][0] = 0; A[0][1] = l2p1x-l1p1x; A[1][1] = l2p1y-l1p1y; A[2][1] = t2-t1; } B[0] += p1x; B[1] += p1y; B[2] += t1; A[0][2] = p1x-p2x; A[1][2] = p1y-p2y; A[2][2] = t1-t2; /* Apply Gauss elimination. */ double* Ap[3]; for (unsigned int i = 0; i < 3; i++) Ap[i] = A[i]; GaussTransform(3, 3, Ap, B); /* Analyse solutions. */ if (nearlyEqual(A[2][2], 0.0)) { if (nearlyEqual(B[2], 0.0)) { /* Segment in same plane as trapezium. */ if (MRA_DEBUG) cerr << "sITS() in same plane" << endl; /* The following cases have to be considered: Segment entirely outside trapezium, segment entirely inside trapezium, $(p1x, p1y, t1)$ inside trapezium, $(p2x, p2y, t2)$ inside trapezium and $(p1x, p1y, t1)$ and $(p2x, p2y, t2)$ outside trapezium but still intersecting with trapezium. */ bool p1in = between(l1p1x, p1x, l1p2x) && between(l1p1y, p1y, l1p2y); bool p2in = between(l2p1x, p2x, l2p2x) && between(l2p1y, p2y, l2p2y); if (p1in && p2in) { if (MRA_DEBUG) cerr << "sITS() entirely in trapezium" << endl; ip1present = true; ip2present = true; ip1x = p1x; ip1y = p1y; ip1t = t1; ip2x = p2x; ip2y = p2y; ip2t = t2; return; } else { if (MRA_DEBUG) cerr << "sITS() not entirely in trapezium" << endl; double l1p1t = 0.0; bool l1p1is = specialSegmentIntersects1( t2-t1, l1p1x, l1p1y, l2p1x, l2p1y, p1x, p1y, p2x, p2y, l1p1t); double l1p2t = 0.0; bool l1p2is = specialSegmentIntersects1( t2-t1, l1p2x, l1p2y, l2p2x, l2p2y, p1x, p1y, p2x, p2y, l1p2t); if (p1in) { if (MRA_DEBUG) cerr << "sITS() p1 in trapezium" << endl; // assert(l1p1is || l1p2is); if (!l1p1is && !l1p2is) { stringstream msg; msg << "Contradicting results for intersection" << endl << " between trapezium and segment (#1)." << endl << "Trapezium is: (" << l1p1x << " " << l1p1y << ") (" << l1p2x << " " << l1p2y << ") (" << l2p1x << " " << l2p1y << ") (" << l2p2x << " " << l2p2y << ")" << endl << "Segment is: (" << p1x << " " << p1y << ") (" << p2x << " " << p2y << ")" << endl << "It is very likely that this has been" << " caused by rounding errors." << endl << "Try adjusting the precision with the " << " mraprec operator (if available in this" << " build of the MovingRegionAlgebra)." << endl; throw invalid_argument(msg.str()); } ip1present = true; ip2present = true; ip1x = p1x; ip1y = p1y; ip1t = t1; if (l1p1is) { ip2x = p1x+(p2x-p1x)*l1p1t/(t2-t1); ip2y = p1y+(p2y-p1y)*l1p1t/(t2-t1); ip2t = l1p1t; } else { ip2x = p1x+(p2x-p1x)*l1p2t/(t2-t1); ip2y = p1y+(p2y-p1y)*l1p2t/(t2-t1); ip2t = l1p2t; } return; } else if (p2in) { if (MRA_DEBUG) cerr << "sITS() p2 in trapezium" << endl; // assert(l1p1is || l1p2is); if (!l1p1is && !l1p2is) { stringstream msg; msg << "Contradicting results for intersection" << endl << " between trapezium and segment (#2)." << endl << "Trapezium is: (" << l1p1x << " " << l1p1y << ") (" << l1p2x << " " << l1p2y << ") (" << l2p1x << " " << l2p1y << ") (" << l2p2x << " " << l2p2y << ")" << endl << "Segment is: (" << p1x << " " << p1y << ") (" << p2x << " " << p2y << ")" << endl << "It is very likely that this has been" << " caused by rounding errors." << endl << "Try adjusting the precision with the " << " mraprec operator (if available in this" << " build of the MovingRegionAlgebra)." << endl; throw invalid_argument(msg.str()); } ip1present = true; ip2present = true; ip2x = p2x; ip2y = p2y; ip2t = t2; if (l1p1is) { ip1x = p1x+(p2x-p1x)*l1p1t/(t2-t1); ip1y = p1y+(p2y-p1y)*l1p1t/(t2-t1); ip1t = l1p1t; } else { ip1x = p1x+(p2x-p1x)*l1p2t/(t2-t1); ip1y = p1y+(p2y-p1y)*l1p2t/(t2-t1); ip1t = l1p2t; } return; } else { if (MRA_DEBUG) cerr << "sITS() neither p1 nor p2 in " << "trapezium" << endl; if (l1p1is && l1p2is) { if (MRA_DEBUG) cerr << "sITS() intersects trapezium" << endl; ip1present = true; ip2present = true; if (l1p1t < l1p2t) { ip1x = p1x+(p2x-p1x)*l1p1t/(t2-t1); ip1y = p1y+(p2y-p1y)*l1p1t/(t2-t1); ip1t = l1p1t; ip2x = p1x+(p2x-p1x)*l1p2t/(t2-t1); ip2y = p1y+(p2y-p1y)*l1p2t/(t2-t1); ip2t = l1p2t; } else { ip1x = p1x+(p2x-p1x)*l1p2t/(t2-t1); ip1y = p1y+(p2y-p1y)*l1p2t/(t2-t1); ip1t = l1p2t; ip2x = p1x+(p2x-p1x)*l1p1t/(t2-t1); ip2y = p1y+(p2y-p1y)*l1p1t/(t2-t1); ip2t = l1p1t; } return; } else { if (MRA_DEBUG) cerr << "sITS() entirely outside " << "trapezium" << endl; // assert(!l1p1is && !l1p2is); if (l1p1is || l1p2is) { stringstream msg; msg << "Contradicting results for intersection" << endl << " between trapezium and segment (#2)." << endl << "Trapezium is: (" << l1p1x << " " << l1p1y << ") (" << l1p2x << " " << l1p2y << ") (" << l2p1x << " " << l2p1y << ") (" << l2p2x << " " << l2p2y << ")" << endl << "Segment is: (" << p1x << " " << p1y << ") (" << p2x << " " << p2y << ")" << endl << "It is very likely that this has been" << " caused by rounding errors." << endl << "Try adjusting the precision with the " << " mraprec operator (if available in this" << " build of the MovingRegionAlgebra)." << endl; throw invalid_argument(msg.str()); } ip1present = false; ip2present = false; return; } } } } else { /* Segment in different plane as trapezium but parallel to trapezium. */ if (MRA_DEBUG) cerr << "sITS() no solution" << endl; ip1present = false; ip2present = false; return; } } else { /* Segment not parallel to trapezium. */ double u = B[2]/A[2][2]; double x = p1x+(p2x-p1x)*u; double y = p1y+(p2y-p1y)*u; double t = t1+(t2-t1)*u; if (MRA_DEBUG) cerr << "sITS() intersection with u=" << u << " (" << x << " " << y << " " << t << ")" << endl; ip2present = false; if (specialInsidePointTrapezium( t, x, y, t1, l1p1x, l1p1y, l1p2x, l1p2y, t2, l2p1x, l2p1y, l2p2x, l2p2y)) { if (MRA_DEBUG) cerr << "sITS() intersection is inside" << endl; ip1present = true; ip1x = x; ip1y = y; ip1t = t; } else { if (MRA_DEBUG) cerr << "sITS() intersection is not inside" << endl; ip1present = false; } return; } } /* 1.1 Relative positions of points and segments 1.1.1 Function ~pointAboveSegment()~ Returns ~true~ if point $(x, y)$ is located left or above or on segment spanned by the points $(p1x, p1y)$ and $(p2x, p2y)$. This matches the definition of the ~insideAbove~ attribute in ~Region~ and ~URegion~ instances. */ static bool pointAboveSegment(double x, double y, double p1x, double p1y, double p2x, double p2y) { if (MRA_DEBUG) cerr << "pointAboveSegment() called p=(" << x << " " << y << ") p1=(" << p1x << " " << p1y << ") p2=(" << p2x << " " << p2y << ")" << endl; if (nearlyEqual(p1x, p2x)) { if (MRA_DEBUG) cerr << "pointAboveSegment() p1x=p2x" << endl; return x <= p1x; } else if (nearlyEqual(p1y, p2y)) { if (MRA_DEBUG) cerr << "pointAboveSegment() p1y=p2y" << endl; return y >= p1y; } else { if (MRA_DEBUG) cerr << "pointAboveSegment() other" << endl; double t = (x-p1x)/(p2x-p1x); double py = p1y+(p2y-p1y)*t; if (MRA_DEBUG) cerr << "pointAboveSegment() py=" << py << endl; return y >= py; } } /* 1.1 Function ~restrictUPointToInterval()~ Create new ~UPoint~ instance in ~rUp~ from ~up~, which is restricted to interval ~iv~. */ static void restrictUPointToInterval(const UPoint& up, const Interval iv, UPoint& rUp) { if (MRA_DEBUG) cerr << "restrictUPointToInterval() called" << endl; if (nearlyEqual(iv.start.ToDouble(), iv.end.ToDouble())) rUp = up; else { double ti = (iv.start.ToDouble() -up.timeInterval.start.ToDouble()) /(up.timeInterval.end.ToDouble() -up.timeInterval.start.ToDouble()); double tf = (iv.end.ToDouble() -up.timeInterval.start.ToDouble()) /(up.timeInterval.end.ToDouble() -up.timeInterval.start.ToDouble()); UPoint dummy( iv, up.p0.GetX()+(up.p1.GetX()-up.p0.GetX())*ti, up.p0.GetY()+(up.p1.GetY()-up.p0.GetY())*ti, up.p0.GetX()+(up.p1.GetX()-up.p0.GetX())*tf, up.p0.GetY()+(up.p1.GetY()-up.p0.GetY())*tf); rUp = dummy; } } /* 1 Supporting classes and class template Supporting classes are those, which are not registered as SECONDO datatypes but are used to implement the SECONDO datatypes ~iregion~, ~uregion~ and ~mregion~. 1.1 Class ~MSegmentData~ This class is used to represent the segments, which are used to represent region units in section \ref{uregion}. 1.1.1 Class definition The class definition has been moved to ~MovingRegionAlgebra.h~. 1.1.1 Constructor \label{collinear} */ MSegmentData::MSegmentData( unsigned int fno, unsigned int cno, unsigned int sno, bool ia, double isx, double isy, double iex, double iey, double fsx, double fsy, double fex, double fey) : faceno(fno), cycleno(cno), segmentno(sno), insideAbove(ia), 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 (MRA_DEBUG) cerr << "MSegmentData::MSegmentData() #2 " << "called counter=[" << faceno << " " << cycleno << " " << segmentno << "] flags=[" << insideAbove << " " << degeneratedInitialNext << " " << degeneratedFinalNext << "] initial=[" << initialStartX << " " << initialStartY << " " << initialEndX << " " << initialEndY << "] final=[" << finalStartX << " " << finalStartY << " " << finalEndX << " " << finalEndY << "]" << endl; /* Calculate whether segment is point in initial or final instant. */ pointInitial = nearlyEqual(isx, iex) && nearlyEqual(isy, iey); pointFinal = nearlyEqual(fsx, fex) && nearlyEqual(fsy, fey); /* Check whether initial and final segment are collinear, */ bool collinear; if (pointInitial && pointFinal) { /* Error: A segment may not be reduced to a point both in initial and final instant. */ if (MRA_DEBUG) cerr << "MSegmentData::MSegmentData() 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 collinear. */ if (MRA_DEBUG) cerr << "MSegmentData::MSegmentData() " << "initial reduced" << endl; collinear = true; } else if (pointFinal) { /* Only final segment reduced to point. Initial and final segment are trivially collinear. */ if (MRA_DEBUG) cerr << "MSegmentData::MSegmentData() " << "final reduced" << endl; collinear = true; } else if (nearlyEqual(isx, iex) && nearlyEqual(fsx, fex)) { /* Both segments are vertical. Check if both segments have the same orientation. */ if (MRA_DEBUG) cerr << "MSegmentData::MSegmentData() " << "both vertical" << endl; collinear = (lowerOrNearlyEqual(isy, iey) && lowerOrNearlyEqual(fsy, fey)) || (greaterOrNearlyEqual(isy, iey) && greaterOrNearlyEqual(fsy, fey)); } else if (nearlyEqual(isx, iex) || nearlyEqual(fsx, fex)) { /* Only initial or final segment is vertical but not both. */ if (MRA_DEBUG) cerr << "MSegmentData::MSegmentData() " << "one vertical" << endl; collinear = false; } else { /* Both segments are not vertical. */ if (MRA_DEBUG) cerr << "MSegmentData::MSegmentData() " << "none vertical" << endl; collinear = abs((iey-isy)/(iex-isx)-(fey-fsy)/(fex-fsx)) <= eps*epsRelaxFactor || abs((iey-isy)*(fex-fsx)-(fey-fsy)*(iex-isx)) <= eps*epsRelaxFactor; if (!collinear) { cerr << setprecision(10) << "parameters for segment orientation comparison:" << endl << " 1. (iey-isy)/(iex-isx) = " << (iey-isy)/(iex-isx) << endl << " 2. (fey-fsy)/(fex-fsx) = " << (fey-fsy)/(fex-fsx) << endl << " 3. (iey-isy)*(fex-fsx) = " << (iey-isy)*(fex-fsx) << endl << " 4. (fey-fsy)*(iex-isx) = " << (fey-fsy)*(iex-isx) << endl << "1. and 2. or 3. and 4. should be equal." <<"("< origIv, Interval restrIv, MSegmentData& rDms) const { if (MRA_DEBUG) cerr << "MSegmentData::restrictToInterval() called" << endl; /* Implementation is straightforward: Copy the attributes, which do not need to be adjusted, and calculate the new initial and final end points. */ rDms.faceno = faceno; rDms.cycleno = cycleno; rDms.segmentno = segmentno; rDms.insideAbove = insideAbove; rDms.degeneratedInitialNext = degeneratedInitialNext; rDms.degeneratedFinalNext = degeneratedFinalNext; rDms.degeneratedInitial = degeneratedInitial; rDms.degeneratedFinal = degeneratedFinal; rDms.pointInitial = pointInitial; rDms.pointFinal = pointFinal; if (nearlyEqual(origIv.end.ToDouble(), origIv.start.ToDouble())) { rDms.initialStartX = initialStartX; rDms.initialStartY = initialStartY; rDms.initialEndX = initialEndX; rDms.initialEndY = initialEndY; rDms.finalStartX = finalStartX; rDms.finalStartY = finalStartY; rDms.finalEndX = finalEndX; rDms.finalEndY = finalEndY; } else { double ti = (restrIv.start.ToDouble()-origIv.start.ToDouble()) /(origIv.end.ToDouble()-origIv.start.ToDouble()); double tf = (restrIv.end.ToDouble()-origIv.start.ToDouble()) /(origIv.end.ToDouble()-origIv.start.ToDouble()); if (MRA_DEBUG) cerr << "MSegmentData::restrictToInterval() ti=" << ti << " tf=" << tf << endl; rDms.initialStartX = initialStartX+(finalStartX-initialStartX)*ti; rDms.initialStartY = initialStartY+(finalStartY-initialStartY)*ti; rDms.initialEndX = initialEndX+(finalEndX-initialEndX)*ti; rDms.initialEndY = initialEndY+(finalEndY-initialEndY)*ti; rDms.finalStartX = initialStartX+(finalStartX-initialStartX)*tf; rDms.finalStartY = initialStartY+(finalStartY-initialStartY)*tf; rDms.finalEndX = initialEndX+(finalEndX-initialEndX)*tf; rDms.finalEndY = initialEndY+(finalEndY-initialEndY)*tf; } } /* 1.1.1.1 Method ~ToString()~ */ string MSegmentData::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 ~TrapeziumSegmentIntersection~ 1.1.1 Class definition The class definition has been moved to ~MovingRegionAlgebra.h~. 1.1.1 Operator ~<~ */ bool TrapeziumSegmentIntersection::operator<( const TrapeziumSegmentIntersection& tsi) const { if (nearlyEqual(t, tsi.t)) { return type < tsi.type; } else return t < tsi.t; } /* 1.1 Class template ~RefinementPartition~ Moved to ~TemporalAlgbra.h~ 1 Data type ~iregion~ 1.1 Class ~IRegion~ 1.1.1 Class definition The class definition has been moved to ~MovingRegionAlgebra.h~. 1.1.1 Constructors */ IRegion::IRegion(bool dummy): Intime(0) { MRA_TRACE; /* This is quite ugly and may not work with other compilers than gcc. Since the ~Intime()~ constructors do not properly initialise their ~value~ attribute (which if of type ~Region~ in this case), there is no better solution right now to assure that ~value~ has a valid DBArray. */ /*Region* tmp = new Region(0); memcpy(&value, tmp, sizeof(*tmp)); delete(tmp);*/ value.SetEmpty(); value.SetDefined(true); SetDefined(true); } IRegion::IRegion(const IRegion& ir) : Intime(ir.instant, ir.value) { MRA_TRACE; if(!ir.IsDefined()){ SetDefined(false); return; } } IRegion::IRegion(const Instant& instant, const Region& region): Intime(instant,region){} /* 1.1.1 Methods for algebra integration 1.1.1.1 Method ~Clone()~ */ IRegion* IRegion::Clone(void) const { MRA_TRACE; return new IRegion(*this); } /* 1.1.1.1 ~DBArray~ access */ int IRegion::NumOfFLOBs() const{ MRA_TRACE; return 1; } Flob* IRegion::GetFLOB(const int i) { MRA_TRACE; assert(i == 0); return value.GetFLOB(0); } /* 1.1 Algebra integration 1.1.1 Function ~IRegionProperty()~ */ static ListExpr IRegionProperty() { MRA_TRACE; ListExpr example = nl->TextAtom(); nl->AppendText(example, "(\"2003-01-10\" ((((1.0 3.5)(2.0 5.5)(3.0 6.5)(4.0 6.5)" "(4.0 5.5)(5.0 4.5)(5.0 2.5)(4.0 1.5)(3.0 1.5))" "((2.0 3.0)(2.0 4.0)(3.0 4.0)(3.0 3.0)))))"); return nl->TwoElemList( nl->FourElemList( nl->StringAtom("Signature"), nl->StringAtom("Example Type List"), nl->StringAtom("List Rep"), nl->StringAtom("Example List")), nl->FourElemList( nl->StringAtom("-> UNIT"), nl->StringAtom("(iregion)"), nl->StringAtom("( )"), example)); } /* 1.1.1 Function ~CheckIRegion()~ */ static bool CheckIRegion(ListExpr type, ListExpr& errorInfo) { MRA_TRACE; return nl->IsEqual(type, IRegion::BasicType()) || nl->IsEqual(type, "intimeregion"); // backward-compatibility! } /* 1.1.1 Function ~CreateIRegion()~ */ static Word CreateIRegion(const ListExpr typeInfo) { if (MRA_DEBUG) cerr << "CreateIRegion() called" << endl; return SetWord(new IRegion(false)); } void* CastIRegion( void* addr ) { return (new (addr) IRegion); } int SizeOfIRegion() { return sizeof(IRegion); } void DeleteIRegion(const ListExpr typeInfo, Word &w){ IRegion* ir = (IRegion*) w.addr; delete ir; w.addr=0; } void CloseIRegion(const ListExpr typeInfo, Word &w){ IRegion* ir = (IRegion*) w.addr; delete ir; w.addr=0; } Word CloneIRegion( const ListExpr typeInfo, const Word& w ) { return SetWord( new IRegion( * ((IRegion*)w.addr))); } Word InIRegion( const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct ){ if(listutils::isSymbolUndefined( instance ) ){ IRegion* res = new IRegion(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); } Region* region = (Region*)InRegion( nl->TheEmptyList(), reg, errorPos, errorInfo, correct).addr; if(!correct){ if(region){ delete region; } delete instant; return SetWord((void*)0); } IRegion* res = new IRegion(*instant, *region); delete instant; delete region; correct = true; return SetWord(res); } /* 1.1.1 Type constructor ~intimeregion~ */ static TypeConstructor intimeregion( IRegion::BasicType(), IRegionProperty, OutIntime, InIRegion, 0, 0, // SaveToList, RestoreFromList CreateIRegion, DeleteIRegion, OpenAttribute, SaveAttribute, // object open and save CloseIRegion, CloneIRegion, CastIRegion, SizeOfIRegion, CheckIRegion ); /* 1 Class ~URegionEmb~ 1.1 Class definition The class definition has been moved to ~MovingRegionAlgebra.h~. 1.1 Constructors */ URegionEmb::URegionEmb( const bool Defined ) : segmentsStartPos(0), segmentsNum(0), bbox(false) { if (MRA_DEBUG) cerr << "URegionEmb::URegionEmb(bool) called" << endl; } URegionEmb::URegionEmb(const Interval& tiv, unsigned int pos) : segmentsStartPos(pos), segmentsNum(0), bbox(false), timeInterval(tiv) { if (MRA_DEBUG) cerr << "URegionEmb::URegionEmb() #2 called" << endl; } URegionEmb::URegionEmb( DbArray* segments, const Interval& tiv, const Region& region, unsigned int pos) : segmentsStartPos(pos), segmentsNum(0), timeInterval(tiv) { if (MRA_DEBUG) cerr << "URegionEmb::URegionEmb() #4 called" << endl; /* The following code adds each segment of the region as constant moving segment to the region unit. Since region units do not use half segments, only one half segment of each segment is considered. Each considered half segment may need to be reversed before it is added to the region unit so that clockwise or counter-clockwise order is maintained within the region unit. */ int cycleStart = 0; for (int i = 0; i < region.Size(); i += 2) { HalfSegment thisHs; region.Get(i, thisHs); HalfSegment nextHs; region.Get(i+2 == region.Size() ? 0 : i+2, nextHs); if (thisHs.GetAttr().cycleno != nextHs.GetAttr().cycleno) { region.Get(cycleStart, nextHs); cycleStart = i+2; } if (MRA_DEBUG) { cerr << "URegionEmb::URegionEmb() i=" << i << endl; cerr << "URegionEmb::URegionEmb() cycleStart=" << cycleStart << endl; cerr << "URegionEmb::URegionEmb() thisHs=" << thisHs << endl; cerr << "URegionEmb::URegionEmb() nextHs=" << nextHs << endl; } if (thisHs.GetRightPoint() == nextHs.GetLeftPoint() || thisHs.GetRightPoint() == nextHs.GetRightPoint()) { if (MRA_DEBUG) cerr << "URegionEmb::URegionEmb() not swapping" << endl; MSegmentData dms(thisHs.GetAttr().faceno, thisHs.GetAttr().cycleno, thisHs.GetAttr().edgeno, thisHs.GetAttr().insideAbove, thisHs.GetLeftPoint().GetX(), thisHs.GetLeftPoint().GetY(), thisHs.GetRightPoint().GetX(), thisHs.GetRightPoint().GetY(), thisHs.GetLeftPoint().GetX(), thisHs.GetLeftPoint().GetY(), thisHs.GetRightPoint().GetX(), thisHs.GetRightPoint().GetY()); dms.SetDegeneratedInitial(DGM_NONE); dms.SetDegeneratedFinal(DGM_NONE); if (MRA_DEBUG) cerr << "URegionEmb::URegionEmb() adding " << dms.ToString() << endl; segments->Put(segmentsStartPos+segmentsNum, dms); } else { if (MRA_DEBUG) cerr << "URegionEmb::URegionEmb() swapping" << endl; MSegmentData dms(thisHs.GetAttr().faceno, thisHs.GetAttr().cycleno, thisHs.GetAttr().edgeno, thisHs.GetAttr().insideAbove, thisHs.GetRightPoint().GetX(), thisHs.GetRightPoint().GetY(), thisHs.GetLeftPoint().GetX(), thisHs.GetLeftPoint().GetY(), thisHs.GetRightPoint().GetX(), thisHs.GetRightPoint().GetY(), thisHs.GetLeftPoint().GetX(), thisHs.GetLeftPoint().GetY()); dms.SetDegeneratedInitial(DGM_NONE); dms.SetDegeneratedFinal(DGM_NONE); if (MRA_DEBUG) cerr << "URegionEmb::URegionEmb() adding " << dms.ToString() << endl; segments->Put(segmentsStartPos+segmentsNum, dms); } segmentsNum++; } Rectangle<2> rbb = region.BoundingBox(); double min[3] = { rbb.MinD(0), rbb.MinD(1), timeInterval.start.ToDouble() }; double max[3] = { rbb.MaxD(0), rbb.MaxD(1), timeInterval.end.ToDouble() }; bbox.Set(true, min, max); } void URegionEmb::SetSegmentsNum(int i){ segmentsNum=i; } void URegionEmb::SetStartPos(int i){ segmentsStartPos=i; } /* 1.1 Methods required to act as unit in ~Mapping~ template 1.1.1 Method ~IsValid()~ */ bool URegionEmb::IsValid(void) const { return true; } /* 1.1.1 Method ~Disjoint()~ */ bool URegionEmb::Disjoint(const URegionEmb& ur) const { return timeInterval.R_Disjoint(ur.timeInterval) || ur.timeInterval.R_Disjoint(timeInterval); } /* 1.1.1 Method ~TU\_Adjacent()~ */ bool URegionEmb::TU_Adjacent(const URegionEmb& ur) const { return timeInterval.R_Adjacent(ur.timeInterval) || ur.timeInterval.R_Adjacent(timeInterval); } /* 1.1.1 Operator ~==~ */ bool URegionEmb::operator==(const URegionEmb& ur) const { return (timeInterval == ur.timeInterval); } /* 1.1.1 Method ~Before()~ */ bool URegionEmb::Before(const URegionEmb& ur) const { return timeInterval.Before(ur.timeInterval); } /* 1.1.1 Method ~Compare()~ */ bool URegionEmb::Compare(const URegionEmb* ur) const { assert(false); return false; } /* 1.1 Moving segment access methods 1.1.1 Method ~GetSegmentsNum()~ */ int URegionEmb::GetSegmentsNum(void) const { if (MRA_DEBUG) cerr << "URegionEmb::GetSegmentsNum() called, num=" << segmentsNum << endl; return segmentsNum; } /* 1.1.2 Method ~GetStartPos()~ */ const int URegionEmb::GetStartPos() const{ if (MRA_DEBUG) cerr << "URegionEmb::GetStartPos() called, sp=" << segmentsStartPos << endl; return segmentsStartPos; } /* 1.1.1 Method ~GetSegment()~ */ void URegionEmb::GetSegment( const DbArray* segments, int pos, MSegmentData& dms) const { if (MRA_DEBUG) cerr << "URegionEmb::GetSegment() called, pos=" << pos << ", segments=" << segments << endl; segments->Get(segmentsStartPos+pos, &dms); } /* 1.1.1 Method ~PutSegment()~ */ void URegionEmb::PutSegment( DbArray* segments, int pos, const MSegmentData& dms, const bool isNew) { if (MRA_DEBUG) cerr << "URegionEmb::PutSegment() called, pos=" << pos << " "<Put(segmentsStartPos+pos, dms); if(isNew){ segmentsNum++; } } /* 1.1.1 Method ~SetSegmentInsideAbove()~ */ void URegionEmb::SetSegmentInsideAbove( DbArray* segments, int pos, bool insideAbove) { if (MRA_DEBUG) cerr << "URegionEmb::GetSegmentLeftOrAbove() called, segments=" << segments << endl; MSegmentData auxDms; segments->Get(segmentsStartPos+pos, &auxDms); MSegmentData dms( auxDms ); dms.SetInsideAbove(insideAbove); segments->Put(segmentsStartPos+pos, dms); } /* 1.1.1 Method ~AddSegment()~ */ bool URegionEmb::AddSegment( DbArray* segments, Region& cr, Region& rDir, unsigned int faceno, unsigned int cycleno, unsigned int segmentno, unsigned int partnerno, DateTime& intervalLen, ListExpr start, ListExpr end) { if (MRA_DEBUG) cerr << "URegionEmb::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) != 4 || !nl->IsAtom(nl->First(start)) || (nl->AtomType(nl->First(start)) != RealType && nl->AtomType(nl->First(start)) != IntType) || !nl->IsAtom(nl->Second(start)) || (nl->AtomType(nl->Second(start)) != RealType && nl->AtomType(nl->Second(start)) != IntType) || !nl->IsAtom(nl->Third(start)) || (nl->AtomType(nl->Third(start)) != RealType && nl->AtomType(nl->Third(start)) != IntType) || !nl->IsAtom(nl->Fourth(start)) || (nl->AtomType(nl->Fourth(start)) != RealType && nl->AtomType(nl->Fourth(start)) != IntType)) throw invalid_argument( " Start point " +nl->ToString(start) +" not in format ( )."); if (nl->ListLength(end) != 4 || !nl->IsAtom(nl->First(end)) || (nl->AtomType(nl->First(end)) != RealType && nl->AtomType(nl->First(end)) != IntType) || !nl->IsAtom(nl->Second(end)) || (nl->AtomType(nl->Second(end)) != RealType && nl->AtomType(nl->Second(end)) != IntType) || !nl->IsAtom(nl->Third(end)) || (nl->AtomType(nl->Third(end)) != RealType && nl->AtomType(nl->Third(end)) != IntType) || !nl->IsAtom(nl->Fourth(end)) || (nl->AtomType(nl->Fourth(end)) != RealType && nl->AtomType(nl->Fourth(end)) != IntType)) throw invalid_argument( " End point " +nl->ToString(end) +" not in format ( )."); /* Create segment from list representation. */ MSegmentData dms(faceno, cycleno, segmentno, false, nl->AtomType(nl->First(start)) == RealType ? nl->RealValue(nl->First(start)) : (double) nl->IntValue(nl->First(start)), nl->AtomType(nl->Second(start)) == RealType ? nl->RealValue(nl->Second(start)) : (double) nl->IntValue(nl->Second(start)), nl->AtomType(nl->First(end)) == RealType ? nl->RealValue(nl->First(end)) : (double) nl->IntValue(nl->First(end)), nl->AtomType(nl->Second(end)) == RealType ? nl->RealValue(nl->Second(end)) : (double) nl->IntValue(nl->Second(end)), nl->AtomType(nl->Third(start)) == RealType ? nl->RealValue(nl->Third(start)) : (double) nl->IntValue(nl->Third(start)), nl->AtomType(nl->Fourth(start)) == RealType ? nl->RealValue(nl->Fourth(start)) : (double) nl->IntValue(nl->Fourth(start)), nl->AtomType(nl->Third(end)) == RealType ? nl->RealValue(nl->Third(end)) : (double) nl->IntValue(nl->Third(end)), nl->AtomType(nl->Fourth(end)) == RealType ? nl->RealValue(nl->Fourth(end)) : (double) nl->IntValue(nl->Fourth(end))); if (MRA_DEBUG) cerr << "URegionEmb::AddSegment() segmentsNum=" << segmentsNum << endl; /* For each of the already existing segments: */ for (int i = segmentsNum-1; i >= 0; i--) { if (MRA_DEBUG) cerr << "URegionEmb::AddSegment() i=" << i << endl; MSegmentData auxExistingDms; segments->Get(segmentsStartPos+i, &auxExistingDms); MSegmentData existingDms( auxExistingDms ); /* 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. */ if (dms.GetDegeneratedInitialNext() < 0 && !dms.GetPointInitial() && !existingDms.GetPointInitial() && ((nearlyEqual( dms.GetInitialStartX(), existingDms.GetInitialStartX()) && nearlyEqual( dms.GetInitialStartY(), existingDms.GetInitialStartY()) && nearlyEqual( dms.GetInitialEndX(), existingDms.GetInitialEndX()) && nearlyEqual( dms.GetInitialEndY(), existingDms.GetInitialEndY())) || (nearlyEqual( dms.GetInitialStartX(), existingDms.GetInitialEndX()) && nearlyEqual( dms.GetInitialStartY(), existingDms.GetInitialEndY()) && nearlyEqual( dms.GetInitialEndX(), existingDms.GetInitialStartX()) && nearlyEqual( dms.GetInitialEndY(), existingDms.GetInitialStartY())))) { if (MRA_DEBUG) cerr << "URegionEmb::AddSegment() " << "degen'ed initial in " << i << endl; dms.SetDegeneratedInitialNext(0); existingDms.SetDegeneratedInitialNext(segmentsNum+1); segments->Put(segmentsStartPos+i, existingDms); } /* Same for the final instant. */ if (dms.GetDegeneratedFinalNext() < 0 && !dms.GetPointFinal() && !existingDms.GetPointFinal() && ((nearlyEqual( dms.GetFinalStartX(), existingDms.GetFinalStartX()) && nearlyEqual( dms.GetFinalStartY(), existingDms.GetFinalStartY()) && nearlyEqual( dms.GetFinalEndX(), existingDms.GetFinalEndX()) && nearlyEqual( dms.GetFinalEndY(), existingDms.GetFinalEndY())) || (nearlyEqual( dms.GetFinalStartX(), existingDms.GetFinalEndX()) && nearlyEqual( dms.GetFinalStartY(), existingDms.GetFinalEndY()) && nearlyEqual( dms.GetFinalEndX(), existingDms.GetFinalStartX()) && nearlyEqual( dms.GetFinalEndY(), existingDms.GetFinalStartY())))) { if (MRA_DEBUG) cerr << "URegionEmb::AddSegment() " << "degen'ed 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() && (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() && dms.GetDegeneratedInitialNext() >= 0 && dms.GetDegeneratedFinalNext() >= 0) { stringstream msg; msg << " 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(); throw invalid_argument(msg.str()); } /* Check if the current segment intersects with the existing segment. Since both a moving segments and are spanning a trapezium in 3d space $(x, y, t)$, this is equivalent to the intersection of two trapeziums. */ unsigned int detailedResult; if ( specialTrapeziumIntersects(intervalLen.ToDouble(), existingDms.GetInitialStartX(), existingDms.GetInitialStartY(), existingDms.GetInitialEndX(), existingDms.GetInitialEndY(), existingDms.GetFinalStartX(), existingDms.GetFinalStartY(), existingDms.GetFinalEndX(), existingDms.GetFinalEndY(), dms.GetInitialStartX(), dms.GetInitialStartY(), dms.GetInitialEndX(), dms.GetInitialEndY(), dms.GetFinalStartX(), dms.GetFinalStartY(), dms.GetFinalEndX(), dms.GetFinalEndY(), detailedResult)) { stringstream msg; msg << " Moving segments intersect (code " << detailedResult << ")." << 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()); } } /* Add half segments to $cr$ and $rDir$ for region check and direction computation. */ double t = intervalLen.IsZero() ? 0 : 0.5; double xs = dms.GetInitialStartX() +(dms.GetFinalStartX()-dms.GetInitialStartX())*t; double ys = dms.GetInitialStartY() +(dms.GetFinalStartY()-dms.GetInitialStartY())*t; double xe = dms.GetInitialEndX() +(dms.GetFinalEndX()-dms.GetInitialEndX())*t; double ye = dms.GetInitialEndY() +(dms.GetFinalEndY()-dms.GetInitialEndY())*t; Point s(true, xs, ys); Point e(true, xe, ye); HalfSegment hs(true, s, e); hs.attr.faceno = faceno; hs.attr.cycleno = cycleno; hs.attr.partnerno = partnerno; hs.attr.edgeno = segmentno; hs.attr.insideAbove = hs.GetLeftPoint() == s; if (MRA_DEBUG) cerr << "URegionEmb::AddSegment() " << dms.ToString() << endl; if (MRA_DEBUG) cerr << "URegionEmb::AddSegment() " << faceno << " " << cycleno << " " << partnerno << " (" << xs << ", " << ys << ")-(" << xe << ", " << ye << ") ia=" << hs.attr.insideAbove << endl; if (!cr.InsertOk(hs)) { stringstream msg; msg << " Region checks for segment failed." << endl << " New segment:" << endl << " Initial: (" << dms.GetInitialStartX() << " " << dms.GetInitialStartY() << ") - (" << dms.GetInitialEndX() << " " << dms.GetInitialEndY() << ")" << endl << " Final: (" << dms.GetFinalStartX() << " " << dms.GetFinalStartY() << ") - (" << dms.GetFinalEndX() << " " << dms.GetFinalEndY(); throw invalid_argument(msg.str()); } cr += hs; if( hs.IsLeftDomPoint() ) { rDir += hs; hs.SetLeftDomPoint( false ); } else { hs.SetLeftDomPoint( true ); rDir += hs; } cr += hs; segments->resize(segmentsStartPos+segmentsNum+1); segments->Put(segmentsStartPos+segmentsNum, dms); segmentsNum++; 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() > max[0]) max[0] = dms.GetInitialStartX(); if (dms.GetFinalStartX() > max[0]) max[0] = dms.GetFinalStartX(); if (dms.GetInitialStartY() > max[1]) max[1] = dms.GetInitialStartY(); if (dms.GetFinalStartY() > max[1]) max[1] = dms.GetFinalStartY(); bbox.Set(true, min, max); } else { double min[3] = { dms.GetInitialStartX() < dms.GetFinalStartX() ? dms.GetInitialStartX() : dms.GetFinalStartX(), dms.GetInitialStartY() < dms.GetFinalStartY() ? dms.GetInitialStartY() : dms.GetFinalStartY(), timeInterval.start.ToDouble() }; double max[3] = { dms.GetInitialStartX() > dms.GetFinalStartX() ? dms.GetInitialStartX() : dms.GetFinalStartX(), dms.GetInitialStartY() > dms.GetFinalStartY() ? dms.GetInitialStartY() : dms.GetFinalStartY(), timeInterval.end.ToDouble() }; bbox.Set(true, min, max); } } catch (invalid_argument& e) { cerr << "-----------------------------------------------------------" << endl << "Checking segment failed." << endl << e.what() << endl << "-----------------------------------------------------------" << endl; return false; } return true; } /* 1.1 Helper methods for ~RestrictedIntersection()~ 1.1.1 Method ~Plumbline()~ */ unsigned int URegionEmb::Plumbline( const DbArray* segments, const UPoint& up, const Interval& iv) const{ if (MRA_DEBUG) cerr << "URegionEmb::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 middle of the interval: */ double t = iv.start.ToDouble() +(iv.end.ToDouble()-iv.start.ToDouble())/2; if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() iv.start=" << iv.start.ToDouble() << " iv.end=" << iv.end.ToDouble() << " t=" << t << endl; double f; /* Calculate the position ~x~, ~y~ of ~up~ for ~t~. */ if (nearlyEqual(up.timeInterval.start.ToDouble(), up.timeInterval.end.ToDouble())) f = 0; else f = (t-up.timeInterval.start.ToDouble()) /(up.timeInterval.end.ToDouble() -up.timeInterval.start.ToDouble()); if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() f=" << f << endl; if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() p0=(" << up.p0.GetX() << " " << up.p0.GetY() << ") p1=(" << up.p1.GetX() << " " << up.p1.GetY() << ")" << endl; double x = up.p0.GetX()+(up.p1.GetX()-up.p0.GetX())*f; double y = up.p0.GetY()+(up.p1.GetY()-up.p0.GetY())*f; if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() x=" << x << " y=" << y << endl; /* Required to calculate the position of each segment for ~t~. */ if (nearlyEqual(timeInterval.start.ToDouble(), timeInterval.end.ToDouble())) f = 0; else f = (t-timeInterval.start.ToDouble()) /(timeInterval.end.ToDouble() -timeInterval.start.ToDouble()); /* ~num~ is used to count the segments above ~(x, y)~. */ unsigned int num = 0; /* Go through all segments... */ for (unsigned int i = 0; i < segmentsNum; i++) { if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() segment #" << i << endl; MSegmentData dms; segments->Get(segmentsStartPos+i, &dms); /* Calculate position of segment at ~t~. */ double p1x = dms.GetInitialStartX() +(dms.GetFinalStartX()-dms.GetInitialStartX())*f; double p1y = dms.GetInitialStartY() +(dms.GetFinalStartY()-dms.GetInitialStartY())*f; double p2x = dms.GetInitialEndX() +(dms.GetFinalEndX()-dms.GetInitialEndX())*f; double p2y = dms.GetInitialEndY() +(dms.GetFinalEndY()-dms.GetInitialEndY())*f; if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() p1x=" << p1x << " p1y=" << p1y << " p2x=" << p2x << " p2y=" << p2y << endl; if (nearlyEqual(p1x, p2x)) { /* Ignore vertical segments. */ if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() " << "vertical, ignored" << endl; } else if (nearlyEqual(p1x, x) && lowerOrNearlyEqual(y, p1y)) { /* ~(x, y)~ is one of the endpoints. Only count it if it is the right endpoint. */ if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() " << "plumbline through start point" << endl; if (p1x > p2x) { if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() counted" << endl; num++; } else { if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() ignored" << endl; } } else if (nearlyEqual(p2x, x) && lowerOrNearlyEqual(y, p2y)) { /* ~(x, y)~ is one of the endpoints. Only count it if it is the right endpoint. */ if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() " << "plumbline through end point" << endl; if (p1x < p2x) { if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() counted" << endl; num++; } else { if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() ignored" << endl; } } else if (!between(p1x, x, p2x)) { /* ~(x, y)~ is not below the segment. */ if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() " << "x not between p1x, p1y, ignored" << endl; } else { /* ~(x, y)~ is in the same ~x~-range as the segment. Count it if the segment is above ~(x, y)~. */ if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() " << "checking for intersection" << endl; if (MRA_DEBUG) { cerr << "URegionEmb::Plumbline() nearlyEqual(p1x, x)=" << nearlyEqual(p1x, x) << endl; cerr << "URegionEmb::Plumbline() nearlyEqual(p2x, x)=" << nearlyEqual(p2x, x) << endl; } // solve p1x+(p2x-p1x)*s = x double s = (x-p1x)/(p2x-p1x); double ys = p1y+(p2y-p1y)*s; if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() ys=" << ys << endl; if (lowerOrNearlyEqual(y, ys)) { if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() below" << endl; num++; } else { if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() not below" << endl; } } if (MRA_DEBUG) cerr << "URegionEmb::Plumbline() num=" << num << endl; } return num; } /* 1.1.1 Method ~RestrictedIntersectionAddUPoint()~ */ void URegionEmb::RestrictedIntersectionAddUPoint(MPoint& res, double starttime, double endtime, bool lc, bool rc, double x0, double y0, double x1, double y1, UPoint*& pending, bool merge) const { if (MRA_DEBUG) { cerr << "URegionEmb::RIAUP() called, merge=" << merge << endl; cerr << "URegionEmb::RIAUP() starttime=" << setprecision(12) << starttime << " endtime=" << endtime << " lc=" << lc << " rc=" << rc << " p0=(" << x0 << " " << y0 << ") p1=(" << x1 << " " << y1 << ")" << endl; } Instant start(instanttype); start.ReadFrom(starttime); Instant end(instanttype); end.ReadFrom(endtime); if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() as instant start=" << start.ToString() << " end=" << end.ToString() << endl; /* Straightforward again. If there is a previous unit pending, try to merge it. If we cannot merge it, put it into ~res~ and start new pending unit. (I am not sure, though, whether merging pending units is required. It may reduce the number of units produced - but is this really a requirement?) */ if (pending) { if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() pending exists" << endl; if (MRA_DEBUG) { cerr << "URegionEmb::RIAUP() pending: [" << setprecision(8) << pending->timeInterval.start.ToString() << " " << pending->timeInterval.end.ToString() << " " << pending->timeInterval.lc << " " << pending->timeInterval.rc << "] (" << pending->p0.GetX() << " " << pending->p0.GetY() << ")-(" << pending->p1.GetX() << " " << pending->p1.GetY() << ")" << endl; cerr << "URegionEmb::RIAUP() current: [" << setprecision(8) << start.ToString() << " " << end.ToString() << " " << lc << " " << rc << "] (" << x0 << " " << y0 << ")-(" << x1 << " " << y1 << ")" << endl; } if (merge && nearlyEqual(pending->timeInterval.end.ToDouble(), starttime) && (pending->timeInterval.rc || lc) && nearlyEqual(pending->p1.GetX(), x0) && nearlyEqual(pending->p1.GetY(), y0)) { if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() intervals match" << endl; if (nearlyEqual(pending->timeInterval.start.ToDouble(), pending->timeInterval.end.ToDouble())) { if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() merge #1" << endl; Interval iv(start, end, true, rc); delete pending; pending = new UPoint(iv, x0, y0, x1, y1); if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() pending=" << pending << endl; return; } else if (nearlyEqual(starttime, endtime)) { if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() merge #2" << endl; Interval iv(pending->timeInterval.start, pending->timeInterval.end, pending->timeInterval.lc, true); UPoint* dummy = new UPoint(iv, pending->p0.GetX(), pending->p0.GetY(), pending->p1.GetX(), pending->p1.GetY()); delete pending; pending = dummy; if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() pending=" << pending << endl; return; } else { if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() checking endpoints" << endl; double f = (pending->timeInterval.start.ToDouble() -starttime) /(endtime-starttime); double x = x0+(x1-x0)*f; double y = y0+(y1-y0)*f; if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() f=" << f << " -> x=" << x << " y=" << y << endl; if (nearlyEqual(pending->p0.GetX(), x) && nearlyEqual(pending->p0.GetY(), y)) { if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() merge #3" << endl; Interval iv(pending->timeInterval.start, end, pending->timeInterval.lc, rc); UPoint* dummy = new UPoint(iv, pending->p0.GetX(), pending->p0.GetY(), x1, y1); delete pending; pending = dummy; if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() pending=" << pending << endl; return; } } } } if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() no merge" << endl; if (pending) { if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() adding " << pending << setprecision(12) << " iv=[" << pending->timeInterval.start.ToDouble() << " " << pending->timeInterval.end.ToDouble() << " " << pending->timeInterval.lc << " " << pending->timeInterval.rc << "]" << endl; if (!(nearlyEqual(pending->timeInterval.start.ToDouble(), pending->timeInterval.end.ToDouble()) && (!pending->timeInterval.lc || !pending->timeInterval.rc))) res.Add(*pending); delete pending; } Interval iv(start, end, lc, rc); pending = new UPoint(iv, x0, y0, x1, y1); if (MRA_DEBUG) cerr << "URegionEmb::RIAUP() pending=" << pending << endl; } /* 1.1.1 Method ~RestrictedIntersectionFindNormal()~ */ void URegionEmb::RestrictedIntersectionFindNormal( const Interval& iv, const UPoint& rUp, MSegmentData& rDms, bool& ip1present, double& ip1x, double& ip1y, double& ip1t, vector& vtsi) const { if (MRA_DEBUG) cerr << "URegionEmb::RIFN() called" << endl; /* Calculate end points of moving segment at time of intersection ~ip1t~. */ double p1x, p1y, p2x, p2y; if (nearlyEqual(iv.start.ToDouble(), iv.end.ToDouble())) { p1x = rDms.GetInitialStartX(); p1y = rDms.GetInitialStartY(); p2x = rDms.GetInitialEndX(); p2y = rDms.GetInitialEndY(); } else { double f = (ip1t-iv.start.ToDouble()) /(iv.end.ToDouble()-iv.start.ToDouble()); p1x = rDms.GetInitialStartX() +(rDms.GetFinalStartX()-rDms.GetInitialStartX())*f; p1y = rDms.GetInitialStartY() +(rDms.GetFinalStartY()-rDms.GetInitialStartY())*f; p2x = rDms.GetInitialEndX() +(rDms.GetFinalEndX()-rDms.GetInitialEndX())*f; p2y = rDms.GetInitialEndY() +(rDms.GetFinalEndY()-rDms.GetInitialEndY())*f; } if (MRA_DEBUG) { cerr << "URegionEmb::RIFN() rUp=(" << rUp.p0.GetX() << " " << rUp.p0.GetY() << ")-(" << rUp.p1.GetX() << " " << rUp.p1.GetY() << ")" << endl; cerr << "URegionEmb::RIFN() p1=(" << p1x << " " << p1y << ") p2=(" << p2x << " " << p2y << ")" << " ip1=(" << ip1x << " " << ip1y << " " << ip1t << ")" << endl; } TrapeziumSegmentIntersection tsi; tsi.x = ip1x; tsi.y = ip1y; tsi.t = ip1t; /* Is the ~UPoint~ instance constant and is it located on the segment? */ if (nearlyEqual(rUp.p0.GetX(), ip1x) && nearlyEqual(rUp.p0.GetY(), ip1y) && nearlyEqual(rUp.p1.GetX(), ip1x) && nearlyEqual(rUp.p1.GetY(), ip1y)) { if (MRA_DEBUG) cerr << "URegionEmb::RIFN() through p0 and p1" << endl; /* Yes, lets see if the moving segment did not touch the ~UPoint~ instance during initial time. If yes, we can deduce from the ~insideAbove~ attribute and the direction of the movement whether the ~URegion~ has been entered or left at the intersection point. If not, we just two identical points, one with TSI\_ENTER and one with TSI\_LEAVE, which indicates that the ~URegion~ has been entered and left in the same instance. */ if (!nearlyEqual(ip1t, iv.start.ToDouble())) { if (pointAboveSegment(ip1x, ip1y, rDms.GetInitialStartX(), rDms.GetInitialStartY(), rDms.GetInitialEndX(), rDms.GetInitialEndY())) { tsi.type = rDms.GetInsideAbove() ? TSI_LEAVE : TSI_ENTER; } else { tsi.type = rDms.GetInsideAbove() ? TSI_ENTER : TSI_LEAVE; } if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } else if (!nearlyEqual(ip1t, iv.end.ToDouble())) { if (pointAboveSegment(ip1x, ip1y, rDms.GetFinalStartX(), rDms.GetFinalStartY(), rDms.GetFinalEndX(), rDms.GetFinalEndY())) { tsi.type = rDms.GetInsideAbove() ? TSI_ENTER : TSI_LEAVE; } else { tsi.type = rDms.GetInsideAbove() ? TSI_LEAVE : TSI_ENTER; } if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } else { if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; tsi.type = TSI_ENTER; vtsi.push_back(tsi); if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; tsi.type = TSI_LEAVE; vtsi.push_back(tsi); } /* Is one of the endpoints of the ~UPoint~ instance located on the segment? If so, check whether the other endpoint is above or below the segment. Together with the value of the ~insideAbove~ attribute, we can deduce whether the ~URegion~ instance has been entered or left. The same is checked for the end of the interval. This is to determine whether point and segment move into the same direction with the segment being faster than the point. In this case, both only touch without the point actually entering the ~URegion~ instance. */ } else if (nearlyEqual(rUp.p0.GetX(), ip1x) && nearlyEqual(rUp.p0.GetY(), ip1y)) { if (MRA_DEBUG) cerr << "URegionEmb::RIFN() through p0" << endl; if (pointAboveSegment(rUp.p1.GetX(), rUp.p1.GetY(), p1x, p1y, p2x, p2y)) { tsi.type = rDms.GetInsideAbove() ? TSI_ENTER : TSI_LEAVE; } else { tsi.type = rDms.GetInsideAbove() ? TSI_LEAVE : TSI_ENTER; } if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); if (pointAboveSegment(rUp.p1.GetX(), rUp.p1.GetY(), rDms.GetFinalStartX(), rDms.GetFinalStartY(), rDms.GetFinalEndX(), rDms.GetFinalEndY())) { tsi.type = tsi.type == TSI_ENTER ? TSI_LEAVE : TSI_ENTER; if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } /* Is the other endpoint of the ~UPoint~ instance located on the segment? If so, see handling of previous case. */ } else if (nearlyEqual(rUp.p1.GetX(), ip1x) && nearlyEqual(rUp.p1.GetY(), ip1y)) { if (MRA_DEBUG) cerr << "URegionEmb::RIFN() through p1" << endl; if (pointAboveSegment(rUp.p0.GetX(), rUp.p0.GetY(), p1x, p1y, p2x, p2y)) { tsi.type = rDms.GetInsideAbove() ? TSI_LEAVE : TSI_ENTER; } else { tsi.type = rDms.GetInsideAbove() ? TSI_ENTER : TSI_LEAVE; } if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); if (pointAboveSegment(rUp.p0.GetX(), rUp.p0.GetY(), rDms.GetInitialStartX(), rDms.GetInitialStartY(), rDms.GetInitialEndX(), rDms.GetInitialEndY())) { tsi.type = tsi.type == TSI_ENTER ? TSI_LEAVE : TSI_ENTER; if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } /* At this point, we do know that one endpoint of the ~UPoint~ instance is left or above the segment. Lets find out which in the remaining two cases. */ } else if (pointAboveSegment(rUp.p0.GetX(), rUp.p0.GetY(), rDms.GetInitialStartX(), rDms.GetInitialStartY(), rDms.GetInitialEndX(), rDms.GetInitialEndY())) { if (MRA_DEBUG) cerr << "URegionEmb::RIFN() p0 above segment" << endl; tsi.type = rDms.GetInsideAbove() ? TSI_LEAVE : TSI_ENTER; if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } else { if (MRA_DEBUG) cerr << "URegionEmb::RIFN() p0 below segment" << endl; tsi.type = rDms.GetInsideAbove() ? TSI_ENTER : TSI_LEAVE; if (MRA_DEBUG) cerr << "URegionEmb::RIFN() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } } /* 1.1.1 Method ~RestrictedIntersectionFindInPlane()~ */ void URegionEmb::RestrictedIntersectionFindInPlane( const Interval& iv, const UPoint& rUp, bool& ip1present, double& ip1x, double& ip1y, double& ip1t, bool& ip2present, double& ip2x, double& ip2y, double& ip2t, vector& vtsi) const { if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() called" << endl; TrapeziumSegmentIntersection tsi; tsi.x = ip1x; tsi.y = ip1y; tsi.t = ip1t; if ((nearlyEqual(ip1x, rUp.p0.GetX()) && nearlyEqual(ip1y, rUp.p0.GetY()) && nearlyEqual(ip2x, rUp.p1.GetX()) && nearlyEqual(ip2y, rUp.p1.GetY())) || (nearlyEqual(ip1x, rUp.p1.GetX()) && nearlyEqual(ip1y, rUp.p1.GetY()) && nearlyEqual(ip2x, rUp.p0.GetX()) && nearlyEqual(ip2y, rUp.p0.GetY()))) { /* The ~URegion~ happily walks entirely along one of the moving segments of the ~URegion~ instance. When the segments is entered, the ~URegion~ instance is entered, and when the segment is left, the ~URegion~ instance is left. */ if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() up on segment" << endl; tsi.type = ip1t < ip2t ? TSI_ENTER : TSI_LEAVE; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); tsi.type = ip1t < ip2t ? TSI_LEAVE : TSI_ENTER; tsi.x = ip2x; tsi.y = ip2y; tsi.t = ip2t; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } else if (nearlyEqual(ip1x, rUp.p0.GetX()) && nearlyEqual(ip1y, rUp.p0.GetY())) { /* The ~URegion~ instance is entered via one of its edge points. */ if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() ip1=p0" << endl; tsi.type = TSI_ENTER; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); tsi.type = TSI_LEAVE; tsi.x = ip2x; tsi.y = ip2y; tsi.t = ip2t; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } else if (nearlyEqual(ip1x, rUp.p1.GetX()) && nearlyEqual(ip1y, rUp.p1.GetY())) { /* The ~URegion~ instance is left via one of its edge points. See previous case. */ if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() ip1=p1" << endl; tsi.type = TSI_LEAVE; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); tsi.type = TSI_ENTER; tsi.x = ip2x; tsi.y = ip2y; tsi.t = ip2t; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } else if (nearlyEqual(ip2x, rUp.p0.GetX()) && nearlyEqual(ip2y, rUp.p0.GetY())) { /* The ~URegion~ instance is entered via one of its edge points. See previous case. */ if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() ip2=p0" << endl; tsi.type = TSI_LEAVE; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); tsi.type = TSI_ENTER; tsi.x = ip2x; tsi.y = ip2y; tsi.t = ip2t; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } else if (nearlyEqual(ip2x, rUp.p1.GetX()) && nearlyEqual(ip2y, rUp.p1.GetY())) { /* The ~URegion~ instance is left via one of its edge points. See previous case. */ if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() ip2=p1" << endl; tsi.type = TSI_ENTER; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); tsi.type = TSI_LEAVE; tsi.x = ip2x; tsi.y = ip2y; tsi.t = ip2t; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } else { /* The ~URegion~ instance is entered and left elsewhere, ie. in the middle of the segments. */ if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() up covers segment" << endl; tsi.type = ip1t < ip2t ? TSI_ENTER : TSI_LEAVE; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); tsi.type = ip1t < ip2t ? TSI_LEAVE : TSI_ENTER; tsi.x = ip2x; tsi.y = ip2y; tsi.t = ip2t; if (MRA_DEBUG) cerr << "URegionEmb::RIFIP() adding " << tsi.type << " " << tsi.x << " " << tsi.y << " " << tsi.t << endl; vtsi.push_back(tsi); } } /* 1.1.1 Method ~RestrictedIntersectionFind()~ */ void URegionEmb::RestrictedIntersectionFind( const DbArray* segments, const UPoint& up, const Interval& iv, vector& vtsi) const { /* Straightforward. Even being slightly cryptic, the debug output provides sufficient context to understand this method. */ if (MRA_DEBUG) cerr << "URegionEmb::RIF() called" << endl; UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); for (unsigned int i = 0; i < segmentsNum; i++) { MSegmentData dms; segments->Get(segmentsStartPos+i, &dms); if (MRA_DEBUG) { cerr << "URegionEmb::RIF() segment #" << i << ": [" << timeInterval.start.ToDouble() << " " << timeInterval.end.ToDouble() << " " << timeInterval.lc << " " << timeInterval.rc << "] " << dms.ToString() << endl; cerr << "URegionEmb::RIF() point is [" << up.timeInterval.start.ToDouble() << " " << up.timeInterval.end.ToDouble() << " " << up.timeInterval.lc << " " << up.timeInterval.rc << "] (" << up.p0.GetX() << " " << up.p0.GetY() << " " << up.p1.GetX() << " " << up.p1.GetY() << ")" << endl; cerr << "URegionEmb::RIF() iv is [" << iv.start.ToDouble() << " " << iv.end.ToDouble() << " " << iv.lc << " " << iv.rc << "]" << endl; } MSegmentData rDms; dms.restrictToInterval(timeInterval, iv, rDms); if (MRA_DEBUG) { cerr << "URegionEmb::RIF() segment restricted to iv is " << rDms.ToString() << endl; cerr << "URegionEmb::RIF() point restricted to iv is (" << rUp.p0.GetX() << " " << rUp.p0.GetY() << " " << rUp.p1.GetX() << " " << rUp.p1.GetY() << ")" << endl; } bool ip1present; double ip1x; double ip1y; double ip1t; bool ip2present; double ip2x; double ip2y; double ip2t; specialIntersectionTrapeziumSegment( iv.start.ToDouble(), iv.end.ToDouble(), rDms.GetInitialStartX(), rDms.GetInitialStartY(), rDms.GetInitialEndX(), rDms.GetInitialEndY(), rDms.GetFinalStartX(), rDms.GetFinalStartY(), rDms.GetFinalEndX(), rDms.GetFinalEndY(), rUp.p0.GetX(), rUp.p0.GetY(), rUp.p1.GetX(), rUp.p1.GetY(), ip1present, ip1x, ip1y, ip1t, ip2present, ip2x, ip2y, ip2t); // debug::start if(MRA_DEBUG){ int i = 0; if (ip1t == 0){i++;} if (1.0 > iv.end.ToDouble()){i++;} if (ip2t == 0){i++;} if ( i > 0 ) cout << __PRETTY_FUNCTION__ << " WARNING: Probably uninitialized values!" << endl; } // debug::end if(ip1present){ if(ip1t < iv.start.ToDouble() || ip1t > iv.end.ToDouble()){ ip1present = false; } } if(ip2present) { if(ip2t < iv.start.ToDouble() || ip2t > iv.end.ToDouble()) { ip2present = false; } } if (MRA_DEBUG) { cerr << "URegionEmb::RIF() ip1present=" << ip1present << endl; cerr << "URegionEmb::RIF() ip2present=" << ip2present << endl; } if (ip1present) { if (MRA_DEBUG) cerr << "URegionEmb::RIF() intersection" << endl; if (ip2present && !(nearlyEqual(ip1x, ip2x) && nearlyEqual(ip1y, ip2y) && nearlyEqual(ip1t, ip2t))) { if (MRA_DEBUG) cerr << "URegionEmb::RIF() in plane, ip1t=" << ip1t << ", ip2t=" << ip2t << ", interval=" << timeInterval.start.ToDouble() << " " << timeInterval.end.ToDouble() << " " << timeInterval.lc << " " << timeInterval.rc << ", restricted=" << iv.start.ToDouble() << " " << iv.end.ToDouble() << " " << iv.lc << " " << iv.rc << endl; RestrictedIntersectionFindInPlane( iv, rUp, ip1present, ip1x, ip1y, ip1t, ip2present, ip2x, ip2y, ip2t, vtsi); } else { if (MRA_DEBUG) cerr << "URegionEmb::RIF() not in plane, ip1t=" << ip1t << ", interval=" << timeInterval.start.ToDouble() << " " << timeInterval.end.ToDouble() << " " << timeInterval.lc << " " << timeInterval.rc << ", restricted=" << iv.start.ToDouble() << " " << iv.end.ToDouble() << " " << iv.lc << " " << iv.rc << endl; RestrictedIntersectionFindNormal( iv, rUp, rDms, ip1present, ip1x, ip1y, ip1t, vtsi); } } } } /* 1.1.1 Method ~RestrictedIntersectionFix()~ */ void URegionEmb::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 (MRA_DEBUG) for (unsigned int i = 0; i < vtsi.size(); i++) cerr << "URegionEmb::RIFix() intersection dump #" << i << " type=" << vtsi[i].type << " ip=[" << vtsi[i].x << " " << vtsi[i].y << " " << vtsi[i].t << "]" << endl; for (unsigned int i = 0; i < vtsi.size(); i++) { if (MRA_DEBUG) cerr << "URegionEmb::RIFix() post-sort i=" << i << endl; unsigned int j; unsigned int numEnter = 0; unsigned int numLeave = 0; double t = vtsi[i].t; double x = vtsi[i].x; double y = vtsi[i].y; for (j = i; j < vtsi.size() && nearlyEqual(vtsi[j].t, t) && nearlyEqual(vtsi[j].x, x) && nearlyEqual(vtsi[j].y, y); j++) { if (vtsi[j].type == TSI_ENTER) numEnter++; else numLeave++; } j--; if (MRA_DEBUG) { cerr << "URegionEmb::RIFix() post-sort j=" << j << endl; cerr << "URegionEmb::RIFix() post-sort numEnter=" << numEnter << endl; cerr << "URegionEmb::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; } else { vtsi[i].type = TSI_LEAVE; for (unsigned int k = i+1; k <= j; k++) vtsi[k].type = TSI_IGNORE; lastType = TSI_LEAVE; } i = j; } else { lastType = vtsi[i].type; } } } /* 1.1.1 Method ~RestrictedIntersectionProcess()~ */ bool URegionEmb::RestrictedIntersectionProcess( const UPoint& up, const Interval& iv, vector& vtsi, MPoint& res, UPoint*& pending, bool merge) const { /* Check all intersections with the same coordinates. Bring them in useful order. For example, if we are inside region at a specific time and arrive at a $TSI\_ENTER$ and $TSI\_LEAVE$ intersection, we should consider the $TSI\_LEAVE$ intersection first. */ if (MRA_DEBUG) cerr << "URegionEmb::RIP() called, interval=" << setprecision(12) << iv.start.ToDouble() << " " << iv.end.ToDouble() << " " << iv.lc << " " << iv.rc << endl; if (vtsi.size() == 0) return false; int prev_i = -1; bool prev_c = false; unsigned int pos = 0; if (MRA_DEBUG && vtsi.size() > 0) cerr << "URegionEmb::RIP() (pre) intersection dump #" << 0 << " type=" << vtsi[0].type << " ip=[" << vtsi[0].x << " " << vtsi[0].y << " " << vtsi[0].t << "]" << endl; for (unsigned int i = 1; i < vtsi.size(); i++) { if (MRA_DEBUG) cerr << "URegionEmb::RIP() intersection dump #" << i << " type=" << vtsi[i].type << " ip=[" << vtsi[i].x << " " << vtsi[i].y << " " << vtsi[i].t << "] pos=" << pos << endl; // if (vtsi[i].type == vtsi[pos].type) { if (vtsi[i].type == TSI_IGNORE) { if (MRA_DEBUG) cerr << "URegionEmb::RIP() removing" << endl; } else { if (MRA_DEBUG) cerr << "URegionEmb::RIP() keeping" << endl; pos++; if (pos < i) vtsi[pos] = vtsi[i]; } } if (MRA_DEBUG) for (unsigned int i = 0; i <= pos; i++) cerr << "URegionEmb::RIP() intersection dump #" << setprecision(12) << i << " type=" << vtsi[i].type << " ip=[" << vtsi[i].x << " " << vtsi[i].y << " " << vtsi[i].t << "]" << endl; for (unsigned int i = 0; i <= pos; i++) { if (MRA_DEBUG) { cerr << "URegionEmb::RIP() intersection dump #" << i << " type=" << vtsi[i].type << " ip=[" << vtsi[i].x << " " << vtsi[i].y << " " << vtsi[i].t << "]" << endl; } if (i == 0 && vtsi[i].type == TSI_LEAVE) { if (MRA_DEBUG) cerr << "URegionEmb::RIP() special case (start)" << endl; bool rc = nearlyEqual(vtsi[i].t, iv.end.ToDouble()) ? iv.rc : true; UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); RestrictedIntersectionAddUPoint( res, iv.start.ToDouble(), vtsi[i].t, iv.lc, rc, rUp.p0.GetX(), rUp.p0.GetY(), vtsi[i].x, vtsi[i].y, pending, merge); prev_i = i; prev_c = rc; } if (i > 0 && vtsi[i].type == TSI_LEAVE) { if (MRA_DEBUG) cerr << "URegionEmb::RIP() normal case" << endl; bool lc = nearlyEqual(vtsi[i-1].t, iv.start.ToDouble()) ? iv.lc : true; if (prev_i >= 0 && nearlyEqual(vtsi[prev_i].t, vtsi[i-1].t) && prev_c) lc = false; bool rc = nearlyEqual(vtsi[i].t, iv.end.ToDouble()) ? iv.rc : true; RestrictedIntersectionAddUPoint( res, vtsi[i-1].t, vtsi[i].t, lc, rc, vtsi[i-1].x, vtsi[i-1].y, vtsi[i].x, vtsi[i].y, pending, merge); prev_i = i; prev_c = rc; } if (i == pos && vtsi[i].type == TSI_ENTER) { if (MRA_DEBUG) cerr << "URegionEmb::RIP() special case (end)" << endl; bool lc = nearlyEqual(vtsi[i].t, iv.start.ToDouble()) ? iv.lc : true; if (prev_i >= 0 && nearlyEqual(vtsi[prev_i].t, vtsi[i].t) && prev_c) lc = false; UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); RestrictedIntersectionAddUPoint( res, vtsi[i].t, iv.end.ToDouble(), lc, iv.rc, vtsi[i].x, vtsi[i].y, rUp.p1.GetX(), rUp.p1.GetY(), pending, merge); prev_i = 0; } } return prev_i >= 0; } /* 1.1 Database operator methods These methods are used to implement the algebra's operators. 1.1.1 Method ~RestrictedIntersection()~ Checks whether the point unit ~up~ intersects this region 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 URegionEmb::RestrictedIntersection(const DbArray* segments, const UPoint& up, const Interval& iv, MPoint& res, UPoint*& pending, bool merge) const { if (MRA_DEBUG) cerr << "URegionEmb::RI() called" << endl; vector vtsi; RestrictedIntersectionFind(segments, up, iv, vtsi); if (MRA_DEBUG) cerr << "URegionEmb::RI() vtsi.size()=" << vtsi.size() << endl; sort(vtsi.begin(), vtsi.end()); RestrictedIntersectionFix(vtsi); if (!RestrictedIntersectionProcess(up, iv, vtsi, res, pending, merge)) { if (MRA_DEBUG) cerr << "URegionEmb::RI() no intersection in whole unit" << endl; unsigned int num = Plumbline(segments, up, iv); if (num > 0 && num % 2 == 1) { UPoint rUp(true); restrictUPointToInterval(up, iv, rUp); RestrictedIntersectionAddUPoint( res, iv.start.ToDouble(), iv.end.ToDouble(), iv.lc, iv.rc, rUp.p0.GetX(), rUp.p0.GetY(), rUp.p1.GetX(), rUp.p1.GetY(), pending, merge); } } } /* 1.1.1 Method ~TemporalFunction()~ */ void URegionEmb::TemporalFunction( const DbArray* segments, const Instant& t, Region& res, bool ignoreLimits ) const { if (MRA_DEBUG){ cerr << "URegionEmb::TemporalFunction() called" << endl; } /* Straightforward again. Calculate segments at specified instant, remove degenerated segments of initial or final instant, when they are not border of any region, and create region. */ assert(t.IsDefined()); assert( ignoreLimits || timeInterval.Contains(t) ); res.Clear(); if(!t.IsDefined() || !(ignoreLimits || timeInterval.Contains(t)) ) { res.SetDefined( false ); return; } res.SetDefined( true ); Instant t0 = timeInterval.start; Instant t1 = timeInterval.end; bool initialInstant = nearlyEqual(t0.ToDouble(), t.ToDouble()); bool finalInstant = nearlyEqual(t1.ToDouble(), t.ToDouble()); double f = nearlyEqual(t0.ToDouble(), t1.ToDouble()) ? 0 : (t-t0)/(t1-t0); int partnerno = 0; res.StartBulkLoad(); for (unsigned int i = 0; i < segmentsNum; i++) { if (MRA_DEBUG){ cerr << "URegionEmb::TemporalFunction() segment #" << i << "/" << segmentsNum << " (" << segmentsStartPos << ")" << endl; } MSegmentData dms; segments->Get(segmentsStartPos+i, &dms); double xs = dms.GetInitialStartX() +(dms.GetFinalStartX()-dms.GetInitialStartX())*f; double ys = dms.GetInitialStartY() +(dms.GetFinalStartY()-dms.GetInitialStartY())*f; double xe = dms.GetInitialEndX() +(dms.GetFinalEndX()-dms.GetInitialEndX())*f; double ye = dms.GetInitialEndY() +(dms.GetFinalEndY()-dms.GetInitialEndY())*f; if (MRA_DEBUG){ cerr << "URegionEmb::TemporalFunction() value is " << xs << " " << ys << " " << xe << " " << ye << endl; } if (nearlyEqual(xs, xe) && nearlyEqual(ys, ye)) { if (MRA_DEBUG){ cerr << "URegionEmb::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 (MRA_DEBUG){ cerr << "URegionEmb::TemporalFunction() " << "ignored degenerated" << endl; } continue; } Point s(true, xs, ys); Point e(true, xe, ye); HalfSegment hs(true, s, e); hs.attr.faceno = 0; hs.attr.cycleno = 0; hs.attr.edgeno = partnerno; hs.attr.partnerno = partnerno++; if (initialInstant && dms.GetDegeneratedInitial() == DGM_INSIDEABOVE){ hs.attr.insideAbove = true; }else if (initialInstant && dms.GetDegeneratedInitial() == DGM_NOTINSIDEABOVE){ hs.attr.insideAbove = false; }else if (finalInstant && dms.GetDegeneratedFinal() == DGM_INSIDEABOVE){ hs.attr.insideAbove = true; }else if (finalInstant && dms.GetDegeneratedFinal() == DGM_NOTINSIDEABOVE){ hs.attr.insideAbove = false; }else{ hs.attr.insideAbove = dms.GetInsideAbove(); } if (MRA_DEBUG){ cerr << "URegionEmb::TemporalFunction() " << "Adding hs=" << hs << endl; } res += hs; hs.SetLeftDomPoint(!hs.IsLeftDomPoint()); if (MRA_DEBUG){ cerr << "URegionEmb::TemporalFunction() " << "Adding hs=" << hs << endl; } res += hs; } res.EndBulkLoad(); if (MRA_DEBUG){ for (int i = 0; i < res.Size(); i++) { HalfSegment hs; res.Get(i, hs); cerr << "URegionEmb::TemporalFunction() segment #" << i << " lp=(" << hs.GetLeftPoint().GetX() << ", " << hs.GetLeftPoint().GetY() << ") rp=(" << hs.GetRightPoint().GetX() << ", " << hs.GetRightPoint().GetY() << ") ldp=" << hs.IsLeftDomPoint() << " attr=" << hs.attr.faceno << " " << hs.attr.cycleno << " " << hs.attr.edgeno << " " << hs.attr.partnerno << " " << hs.attr.insideAbove << endl; } } } /* 1.1.1 Method ~BoundingBox()~ */ const Rectangle<3> URegionEmb::BoundingBox(const Geoid* geoid /*=0*/) const { if (MRA_DEBUG) cerr << "URegionEmb::BoundingBox() called" << endl; if(geoid){ cerr << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." << endl; assert( !geoid ); // TODO: implement spherical geometry case } return bbox; } /* 1.1 In and out functions 1.1.1 Function ~InURegionEmbedded()~ */ static URegionEmb* InURegionEmbedded( const ListExpr instance, const int errorPos, ListExpr& errorInfo, DbArray* segments, unsigned int segmentsStartPos) { if (MRA_DEBUG) cerr << "InURegionEmbedded() called, segmentsStartPos=" << segmentsStartPos << endl; /* Please that ~Region~ creation is done as shown in ~SpatialAlgebra~. See there for more details. */ if (nl->ListLength(instance) == 0) { cerr << "uregion not in format ( *)" << endl; return 0; } if (MRA_DEBUG) cerr << "InURegionEmbedded() ( *) found" << endl; ListExpr interval = nl->First(instance); if (nl->ListLength(interval) != 4 || !nl->IsAtom(nl->First(interval)) || (nl->AtomType(nl->First(interval)) != StringType && nl->AtomType(nl->First(interval)) != RealType) || !nl->IsAtom(nl->Second(interval)) || (nl->AtomType(nl->Second(interval)) != StringType && nl->AtomType(nl->Second(interval)) != RealType) || !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 format " << "( )" << endl; return 0; } bool correct; Instant *start = (Instant *) InInstant(nl->TheEmptyList(), nl->First(interval), errorPos, errorInfo, correct).addr; if (!correct) { cerr << "uregion interval invalid start time" << endl; return 0; } Instant *end = (Instant *) InInstant(nl->TheEmptyList(), nl->Second(interval), errorPos, errorInfo, correct ).addr; if (!correct) { cerr << "uregion interval invalid end time" << endl; correct = false; delete start; return 0; } bool lc = nl->BoolValue(nl->Third(interval)); bool rc = nl->BoolValue(nl->Fourth(interval)); if (end->ToDouble() < start->ToDouble() || (nearlyEqual(start->ToDouble(), end->ToDouble()) && !(lc && rc))) { cerr << "uregion invalid interval" << endl; delete start; delete end; return 0; } Interval tinterval(*start, *end, lc, rc); DateTime intervalLen = *end-*start; delete start; delete end; /* Create ~URegion~ instance and pass storage of segments, if we received any. */ URegionEmb* uregion = new URegionEmb(tinterval, segmentsStartPos); int pointno = -1; unsigned int faceno = 0; unsigned int partnerno = 0; ListExpr faces = nl->Second(instance); Region cr(0); cr.StartBulkLoad(); if (nl->ListLength(faces) == 0) { cerr << "uregion should contain at least one face" << endl; delete uregion; return 0; } /* ... all this is similar to ~Region~ creation in ~SpatialAlgebra~... */ while (!nl->IsEmpty(faces)) { if (MRA_DEBUG) cerr << "InURegionEmbedded() face #" << faceno << endl; ListExpr cycles = nl->First(faces); if (nl->ListLength(cycles) == 0) { cerr << "uregion face should contain at least one cycle" << endl; delete uregion; return 0; } unsigned int cycleno = 0; while (!nl->IsEmpty(cycles)) { if (MRA_DEBUG) cerr << "InURegionEmbedded() cycle #" << cycleno << endl; Region rDir(0); rDir.StartBulkLoad(); ListExpr cyclepoints = nl->First(cycles); if (nl->ListLength(cyclepoints) < 3) { cerr << "uregion cycle should contain at " << "least three points" << endl; delete uregion; return 0; } ListExpr firstPoint = nl->First(cyclepoints); ListExpr prevPoint = 0; unsigned int initialSegmentsNum = uregion->GetSegmentsNum(); while (!nl->IsEmpty(cyclepoints)) { if (MRA_DEBUG) cerr << "InURegionEmbedded() point #" << pointno << endl; ListExpr point = nl->First(cyclepoints); if (prevPoint != 0 && !uregion->AddSegment(segments, cr, rDir, faceno, cycleno, pointno, partnerno, intervalLen, prevPoint, point)) { cerr << "uregion's segment checks failed" << endl; delete uregion; return 0; } prevPoint = point; cyclepoints = nl->Rest(cyclepoints); pointno++; partnerno++; } if (!uregion->AddSegment(segments, cr, rDir, faceno, cycleno, pointno, partnerno, intervalLen, prevPoint, firstPoint)) { cerr << "uregion's segment checks failed" << endl; delete uregion; return 0; } partnerno++; rDir.EndBulkLoad(true, true, false, false); bool direction = rDir.GetCycleDirection(); int h = cr.Size()-(rDir.Size()*2); int i = initialSegmentsNum; while (h < cr.Size()) { HalfSegment hsInsideAbove; bool insideAbove; cr.Get(h, hsInsideAbove); if (MRA_DEBUG) cerr << "InURegionEmbedded() i=" << i << " insideAbove=" << hsInsideAbove.attr.insideAbove << endl; if (direction == hsInsideAbove.attr.insideAbove) insideAbove = false; else insideAbove = true; if (cycleno > 0) insideAbove = !insideAbove; //hsInsideAbove.attr.insideAbove = insideAbove; //cr.UpdateAttr(h, hsInsideAbove.attr); //cr.Get(h+1, &hsInsideAbove); //hsInsideAbove.attr.insideAbove = insideAbove; //cr.UpdateAttr(h+1, hsInsideAbove.attr); uregion->SetSegmentInsideAbove(segments, i, insideAbove); h += 2; i++; } cycles = nl->Rest(cycles); cycleno++; } faces = nl->Rest(faces); faceno++; } cr.EndBulkLoad(); //bool nonTrivialInitial = false; //bool nonTrivialFinal = false; if (MRA_DEBUG) for (int i = 0; i < uregion->GetSegmentsNum(); i++) { MSegmentData dms; uregion->GetSegment(segments, i, dms); cerr << "InURegionEmbedded() segment #" << i << ": " << dms.ToString() << endl; } /* This is different from ~Region~ handling in ~SpatialAlgebra~. We have to go through the lists of degenerated segments and count how often a region is inside above in each list. If there are more inside above segments than others, we need one inside above segment for the ~TemporalFunction()~ and set all others to ignore. Vice version 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++) { MSegmentData auxDms; uregion->GetSegment(segments, i, auxDms); MSegmentData dms( auxDms ); //if (!dms.GetPointInitial() && dms.GetDegeneratedInitialNext() < 0) // nonTrivialInitial = true; //if (!dms.GetPointFinal() && dms.GetDegeneratedFinalNext() < 0) // nonTrivialFinal = true; if (dms.GetDegeneratedInitial() == DGM_UNKNOWN) { if (dms.GetDegeneratedInitialNext() >= 0) { MSegmentData auxDegenDms; MSegmentData 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 (MRA_DEBUG) cerr << "InURegionEmbedded() 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 (MRA_DEBUG) cerr << "InURegionEmbedded() 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) { MSegmentData auxDegenDms; MSegmentData 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 (MRA_DEBUG) cerr << "InURegionEmbedded() 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 (MRA_DEBUG) cerr << "InURegionEmbedded() 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 (MRA_DEBUG) for (int i = 0; i < uregion->GetSegmentsNum(); i++) { MSegmentData dms; uregion->GetSegment(segments, i, dms); cerr << "InURegionEmbedded() resulting segment #" << i << ": " << dms.ToString() << endl; } return uregion; } /* 1.1.1 Function ~OutURegionEmbedded()~ */ static ListExpr OutURegionEmbedded( const URegionEmb* ur, DbArray* segments) { if (MRA_DEBUG) cerr << "OutURegionEmbedded() called" << endl; /* Conversion to list representation is straightforward. Just loop through faces, cylces and segments and make sure that it is realised when one of these changes. */ int num = ur->GetSegmentsNum(); ListExpr faces = nl->TheEmptyList(); ListExpr facesLastElem = faces; ListExpr face = nl->TheEmptyList(); ListExpr faceLastElem = face; ListExpr cycle = nl->TheEmptyList(); ListExpr cycleLastElem = cycle; for (int i = 0; i < num; i++) { if (MRA_DEBUG) cerr << "OutURegionEmbedded() segment #" << i << endl; MSegmentData dms; ur->GetSegment(segments, i, dms); if (MRA_DEBUG) cerr << "OutURegionEmbedded() returned, dms=" << &dms << endl; if (MRA_DEBUG) cerr << "OutURegionEmbedded() point is " << dms.GetFaceNo() << " " << dms.GetCycleNo() << " (" << dms.GetInitialStartX() << ", " << dms.GetInitialStartY() << ", " << dms.GetFinalStartX() << ", " << dms.GetFinalStartY() << ")" << endl; ListExpr p = nl->FourElemList( nl->RealAtom(dms.GetInitialStartX()), nl->RealAtom(dms.GetInitialStartY()), nl->RealAtom(dms.GetFinalStartX()), nl->RealAtom(dms.GetFinalStartY())); if (cycle == nl->TheEmptyList()) { if (MRA_DEBUG) cerr << "OutURegionEmbedded() new cycle" << endl; cycle = nl->OneElemList(p); cycleLastElem = cycle; } else { if (MRA_DEBUG) cerr << "OutURegionEmbedded() existing cycle" << endl; cycleLastElem = nl->Append(cycleLastElem, p); } MSegmentData nextDms; if (i < num-1) ur->GetSegment(segments, i+1, nextDms); if (i == num-1 || dms.GetCycleNo() != nextDms.GetCycleNo() || dms.GetFaceNo() != nextDms.GetFaceNo()) { if (MRA_DEBUG) cerr << "OutURegionEmbedded() end of cycle" << endl; if (face == nl->TheEmptyList()) { if (MRA_DEBUG) cerr << "OutURegionEmbedded() new face" << endl; face = nl->OneElemList(cycle); faceLastElem = face; } else { if (MRA_DEBUG) cerr << "OutURegionEmbedded() existing face" << endl; faceLastElem = nl->Append(faceLastElem, cycle); } if (i == num-1 || dms.GetFaceNo() != nextDms.GetFaceNo()) { if (MRA_DEBUG) cerr << "OutURegionEmbedded() 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; } } ListExpr res = nl->TwoElemList( nl->FourElemList( 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)), faces); return res; } /* 1 Data type ~uregion~ 1.1 Class ~URegion~ 1.1.1 Class definition The class definition has been moved to ~MovingRegionAlgebra.h~. 1.1.1 Constructors */ URegion::URegion(unsigned int n) : SpatialTemporalUnit(true), segments(n) { SetDefined(true); if (MRA_DEBUG) cerr << "URegion::URegion() #1 called" << endl; } bool msegcompare(const MSegmentData& s1, const MSegmentData& s2){ if(s1.GetFaceNo() < s1.GetFaceNo()) return true; if(s1.GetFaceNo() > s1.GetFaceNo()) return false; if(s1.GetCycleNo() < s1.GetCycleNo()) return true; if(s1.GetCycleNo() > s1.GetCycleNo()) return false; if(s1.GetSegmentNo() < s1.GetSegmentNo()) return true; if(s1.GetSegmentNo() > s1.GetSegmentNo()) return false; // should be unique return false; } URegion::URegion(vector linelist, const Interval& tiv, bool simple) : SpatialTemporalUnit(true), segments(0) { Interval newTiv; newTiv.CopyFrom(tiv); uremb= URegionEmb(newTiv, 0); timeInterval = newTiv; if(simple){ sort(linelist.begin(),linelist.end(), msegcompare); vector::iterator it; for(it = linelist.begin(); it != linelist.end(); it++){ AddSegment(*it); } SetDefined(true); return; } while(linelist.size() > 0) { int index = getLeftLower(linelist); MSegmentData first = linelist[index]; #ifdef MR_DEBUG cout< 2) { #ifdef MR_DEBUG cout<<" true"< &linelist) { int res = 0; for(unsigned int i = 1; i < linelist.size(); i++) { Point leftIs = Point(true, linelist[res]. GetInitialStartX(), linelist[res].GetInitialStartY()); Point leftIe = Point(true, linelist[res].GetInitialEndX(), linelist[res].GetInitialEndY()); Point leftFs = Point(true, linelist[res].GetFinalStartX(), linelist[res].GetFinalStartY()); Point leftFe = Point(true, linelist[res].GetFinalEndX(), linelist[res].GetFinalEndY()); Point llIs = Point(true, linelist[i].GetInitialStartX(), linelist[i].GetInitialStartY()); Point llIe = Point(true, linelist[i].GetInitialEndX(), linelist[i].GetInitialEndY()); Point llFs = Point(true, linelist[i].GetFinalStartX(), linelist[i].GetFinalStartY()); Point llFe = Point(true, linelist[i].GetFinalEndX(), linelist[i].GetFinalEndY()); if(leftIs.GetX()>llIs.GetX() || (AlmostEqual(leftIs.GetX(),llIs.GetX()&& leftIs.GetY() > llIs.GetY()))) { res = i; continue; } if(AlmostEqual(leftIs, llIs)) { if((leftIe.GetY() > llIe.GetY()) || ((AlmostEqual(leftIe.GetY(), llIe.GetY())) && (leftIe.GetX() > llIe.GetX()))) { res = i; continue; } if(AlmostEqual(leftIe, llIe)) { if(leftFs > llFs) { res = i; continue; } if(AlmostEqual(leftFs, llFs)) { if((leftFe.GetY() > llFe.GetY()) || ((AlmostEqual(leftFe.GetY(), llFe.GetY())) && (leftFe.GetX() > llFe.GetX()))) { res = i; continue; } } } } } return(res); } int URegion :: findNext(const vector &linelist, const MSegmentData dms) { for(unsigned int i = 0; i < linelist.size(); i++) { if(matches(linelist[i], dms)) return(i); } return(-1); } int URegion :: findNextToRight(const vector &linelist, const MSegmentData dms) { for(unsigned int i = 0; i < linelist.size(); i++) { if(matchesToRight(dms, linelist[i])) return(i); } return(-1); } bool URegion :: matches(const MSegmentData &dms1, const MSegmentData &dms2) { if(matchesLeft(dms1, dms2) || matchesRight(dms1, dms2)) return(true); return(false); } bool URegion :: matchesLeft(const MSegmentData &dms1, const MSegmentData &dms2) { if(dms1.GetFaceNo() != dms2.GetFaceNo()) return(false); if(dms1.GetCycleNo() != dms2.GetCycleNo()) return(false); double isx1 = dms1.GetInitialStartX(); double isx2 = dms2.GetInitialStartX(); double isy1 = dms1.GetInitialStartY(); double isy2 = dms2.GetInitialStartY(); double iex1 = dms1.GetInitialEndX(); double iey1 = dms1.GetInitialEndY(); double iey2 = dms2.GetInitialEndY(); double fsx1 = dms1.GetFinalStartX(); double fsx2 = dms2.GetFinalStartX(); double fsy1 = dms1.GetFinalStartY(); double fsy2 = dms2.GetFinalStartY(); double fex1 = dms1.GetFinalEndX(); double fey1 = dms1.GetFinalEndY(); double fey2 = dms2.GetFinalEndY(); if(AlmostEqual(isx1, isx2) && AlmostEqual(isy1, isy2) && AlmostEqual(fsx1, fsx2) && AlmostEqual(fsy1, fsy2) && !(AlmostEqual(iex1, iex1) && AlmostEqual(iey1, iey2) && AlmostEqual(fex1, fex1) && AlmostEqual(fey1, fey2))) { return(true); } if(AlmostEqual(iex1, isx2) && AlmostEqual(iey1, isy2) && AlmostEqual(fex1, fsx2) && AlmostEqual(fey1, fsy2) && !(AlmostEqual(isx1, iex1) && AlmostEqual(isy1, iey2) && AlmostEqual(fsx1, fex1) && AlmostEqual(fsy1, fey2))) { return(true); } return(false); } bool URegion :: matchesRight(const MSegmentData &dms1, const MSegmentData &dms2) { if(dms1.GetFaceNo() != dms2.GetFaceNo()) return(false); if(dms1.GetCycleNo() != dms2.GetCycleNo()) return(false); double isx1 = dms1.GetInitialStartX(); double isy1= dms1.GetInitialStartY(); double isy2 = dms2.GetInitialStartY(); double iex1 = dms1.GetInitialEndX(); double iex2 = dms2.GetInitialEndX(); double iey1 = dms1.GetInitialEndY(); double iey2 = dms2.GetInitialEndY(); double fsx1= dms1.GetFinalStartX(); double fsy1 = dms1.GetFinalStartY(); double fsy2 = dms2.GetFinalStartY(); double fex1 = dms1.GetFinalEndX(); double fex2 = dms2.GetFinalEndX(); double fey1 = dms1.GetFinalEndY(); double fey2 = dms2.GetFinalEndY(); if(AlmostEqual(isx1, iex2) && AlmostEqual(isy1, iey2) && AlmostEqual(fsx1, fex2) && AlmostEqual(fsy1, fey2) && !(AlmostEqual(iex1, isx1) && AlmostEqual(iey1, isy2) && AlmostEqual(fex1, fsx1) && AlmostEqual(fey1, fsy2))) { return(true); } if(AlmostEqual(iex1, iex2) && AlmostEqual(iey1, iey2) && AlmostEqual(fex1, fex2) && AlmostEqual(fey1, fey2) && !(AlmostEqual(isx1, isx1) && AlmostEqual(isy1, isy2) && AlmostEqual(fsx1, fsx1) && AlmostEqual(fsy1, fsy2))) { return(true); } return(false); } bool URegion::matchesToRight(const MSegmentData &dms1,const MSegmentData &dms2) { if(dms1.GetFaceNo() != dms2.GetFaceNo()) return(false); if(dms1.GetCycleNo() != dms2.GetCycleNo()) return(false); double isx1 = dms1.GetInitialStartX(); double isx2 = dms2.GetInitialStartX(); double isy1 = dms1.GetInitialStartY(); double isy2 = dms2.GetInitialStartY(); double iex1 = dms1.GetInitialEndX(); double iex2 = dms2.GetInitialEndX(); double iey1 = dms1.GetInitialEndY(); double iey2 = dms2.GetInitialEndY(); double fsx1 = dms1.GetFinalStartX(); double fsx2 = dms2.GetFinalStartX(); double fsy1 = dms1.GetFinalStartY(); double fsy2 = dms2.GetFinalStartY(); double fex1 = dms1.GetFinalEndX(); double fex2 = dms2.GetFinalEndX(); double fey1 = dms1.GetFinalEndY(); double fey2 = dms2.GetFinalEndY(); if(AlmostEqual(iex1, isx2) && AlmostEqual(iey1, isy2) && AlmostEqual(fex1, fsx2) && AlmostEqual(fey1, fsy2) && !(AlmostEqual(isx1, iex1) && AlmostEqual(isy1, iey2) && AlmostEqual(fsx1, fex1) && AlmostEqual(fsy1, fey2))) { return(true); } if(AlmostEqual(iex1, iex2) && AlmostEqual(iey1, iey2) && AlmostEqual(fex1, fex2) && AlmostEqual(fey1, fey2) && !(AlmostEqual(isx1, isx1) && AlmostEqual(isy1, isy2) && AlmostEqual(fsx1, fsx1) && AlmostEqual(fsy1, fsy2))) { return(true); } return(false); } void URegion :: AddURegion(URegion *newRegion) { if(timeInterval != newRegion->timeInterval) { throw invalid_argument("Intervals are not equal"); } const DbArray *lines = newRegion->GetMSegmentData(); for(int i = 0; i < lines->Size(); i++) { MSegmentData line; lines->Get(i, line); AddSegment(line); } } void URegion::AddSegment(MSegmentData 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() > max[0]) max[0] = newSeg.GetInitialStartX(); if (newSeg.GetFinalStartX() > max[0]) max[0] = newSeg.GetFinalStartX(); if (newSeg.GetInitialStartY() > max[1]) max[1] = newSeg.GetInitialStartY(); if (newSeg.GetFinalStartY() > max[1]) max[1] = newSeg.GetFinalStartY(); uremb.SetBBox(Rectangle<3>(true, min, max)); } else { double min[3] = { newSeg.GetInitialStartX() < newSeg.GetFinalStartX() ? newSeg.GetInitialStartX() : newSeg.GetFinalStartX(), newSeg.GetInitialStartY() < newSeg.GetFinalStartY() ? newSeg.GetInitialStartY() : newSeg.GetFinalStartY(), uremb.timeInterval.start.ToDouble() }; double max[3] = { newSeg.GetInitialStartX() > newSeg.GetFinalStartX() ? newSeg.GetInitialStartX() : newSeg.GetFinalStartX(), newSeg.GetInitialStartY() > newSeg.GetFinalStartY() ? newSeg.GetInitialStartY() : newSeg.GetFinalStartY(), uremb.timeInterval.end.ToDouble() }; uremb.SetBBox(Rectangle<3>(true, min, max)); } } URegion::URegion(int i, MRegion& mr): SpatialTemporalUnit(true), segments(0) { assert( mr.IsDefined() ); assert( i>=0 ); assert( iGet( s+startSeg, segment ); uremb.PutSegment(&segments, s, segment, true); } SetDefined( true ); } URegionEmb& URegionEmb::operator=(const URegionEmb& U) { segmentsStartPos = U.segmentsStartPos; segmentsNum = U.segmentsNum; bbox = U.bbox; timeInterval = U.timeInterval; return *this; } size_t URegionEmb::HashValue() const{ return ( timeInterval.start.HashValue() ^ timeInterval.end.HashValue() ); } /* 1.1.1 Methods for database operators 1.1.1.1 Method ~BoundingBox()~ */ const Rectangle<3> URegion::BoundingBox(const Geoid* geoid /*=0*/) const { if (MRA_DEBUG) cerr << "URegion::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 ~At()~ This method is not part of the bachelor thesis but a stub is required to make ~URegion~ non-abstract. To assure that accidential calls of this method are recognized, its body contains a failed assertion. */ bool URegion::At(const Region& val, TemporalUnit& result) const { if (MRA_DEBUG) cerr << "URegion::At() called" << endl; assert( IsDefined() ); assert( val.IsDefined() ); cerr << __PRETTY_FUNCTION__ << " not implemented!" << endl; assert(false); URegion* res = static_cast(&result); res->SetDefined( false ); return false; } /* 1.1.1.1 Method ~Passes()~ This method is not part of the bachelor thesis but a stub is required to make ~URegion~ non-abstract. To assure that accidential calls of this method are recognized, its body contains a failed assertion. */ bool URegion::Passes(const Region& val) const { if (MRA_DEBUG) cerr << "URegion::At() called" << endl; assert( IsDefined() ); assert( val.IsDefined() ); cerr << __PRETTY_FUNCTION__ << " not implemented!" << endl; assert(false); return false; } /* 1.1.1.1 Method ~TemporalFunction()~ */ void URegion::TemporalFunction(const Instant& t, Region& res, bool ignoreLimits ) const { if (MRA_DEBUG) cerr << "URegion::TemporalFunction() called" << endl; res.Clear(); if( !IsDefined() || !t.IsDefined() || !(ignoreLimits || timeInterval.Contains(t) ) ) { res.SetDefined( false ); } else { res.SetDefined( true ); uremb.TemporalFunction(&segments, t, res, ignoreLimits); } } /* 1.1.1 Methods for algebra integration 1.1.1.1 Method ~Clone()~ */ URegion* URegion::Clone(void) const { if (MRA_DEBUG) cerr << "URegion::Clone() called" << endl; URegion* res = new URegion( (unsigned int)0 ); res->CopyFrom(this); res->SetDefined( this->del.isDefined ); return res; } /* 1.1.1.1 Method ~CopyFrom()~ */ void URegion::CopyFrom(const Attribute* right) { if (MRA_DEBUG) cerr << "URegion::CopyFrom() called" << endl; const URegion* ur = (const URegion*) right; *this = *ur; this->SetDefined( ur->IsDefined() ); } /* Assignment operator */ URegion& URegion::operator= ( const URegion& U) { if(!U.IsDefined()) { uremb = U.uremb; segments = U.segments; SetDefined(false); return *this; } timeInterval = U.timeInterval; // copy units copy of deftime! uremb = U.uremb; // copy bbox, timeInterval, segmentsNum uremb.SetStartPos(0); // set uremb.segmentsStartPos = 0 del.isDefined = U.del.isDefined; int start = U.uremb.GetStartPos(); int numsegs = U.uremb.GetSegmentsNum(); segments.clean(); segments.resize( U.uremb.GetSegmentsNum() ); for( int i=0 ; iIsDefined() ) return (nl->SymbolAtom(Symbol::UNDEFINED())); return OutURegionEmbedded( ur->GetEmbedded(), (DbArray*) ur->GetFLOB(0)); } /* 1.1.1 Function ~InURegion()~ */ static Word InURegion(const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct) { if (MRA_DEBUG) cerr << "InURegion() called" << endl; URegion* ur = new URegion((unsigned int)0); // Check for undefined value if ( listutils::isSymbolUndefined( instance ) ) { ur->SetDefined(false); correct = true; return SetWord ( ur ); } URegionEmb* uremb = InURegionEmbedded( instance, errorPos, errorInfo, (DbArray*) ur->GetFLOB(0), 0); if (!uremb) { cerr << "Could not grok list representation of region unit." << endl; delete ur; correct = false; return SetWord(Address(0)); } ur->timeInterval = uremb->timeInterval; ur->SetEmbedded(uremb); ur->SetDefined(true); delete uremb; correct = true; return SetWord(Address(ur)); } /* 1.1.1 Function ~URegionProperty()~ */ static ListExpr URegionProperty() { if (MRA_DEBUG) cerr << "URegionProperty() called" << endl; ListExpr listrep = nl->TextAtom(); nl->AppendText(listrep, "( *), where is " "( ) and where " " is ( *), " "where and are " "( ), representing " "start X, start Y, end X and end Y values."); ListExpr example = nl->TextAtom(); nl->AppendText(example, "((0.0 10.0 TRUE TRUE)" "((((1.0 3.5 1.5 1.5)" "(2.0 5.5 3.0 4.5)" "(3.0 6.5 3.5 5.0)" "(4.0 6.5 5.5 5.0)" "(4.0 5.5 5.5 4.5)" "(5.0 4.5 7.5 2.5)" "(5.0 2.5 7.5 1.0)" "(4.0 1.5 7.0 0.5)" "(3.0 1.5 2.5 0.5))" "((2.0 3.0 3.0 2.0)" "(2.0 4.0 3.0 3.0)" "(3.0 4.0 4.0 3.0)" "(3.0 3.0 4.0 2.0)))))"); 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("(uregion)"), listrep, example, remarks)); } /* 1.1.1 Function ~CheckURegion()~ */ static bool CheckURegion(ListExpr type, ListExpr& errorInfo) { if (MRA_DEBUG) cerr << "CheckURegion() called" << endl; return nl->IsEqual(type, URegion::BasicType()); } /* 1.1.1 Function ~CreateURegion()~ */ static Word CreateURegion(const ListExpr typeInfo) { if (MRA_DEBUG) cerr << "CreateURegion() called" << endl; return (SetWord(new URegion((unsigned int)0))); } /* 1.1.1 Function ~DeleteURegion()~ */ static void DeleteURegion(const ListExpr typeInfo, Word& w) { if (MRA_DEBUG) cerr << "DeleteURegion() called" << endl; URegion *ur = (URegion*)w.addr; delete ur; w.addr = 0; } /* 1.1.1 Function ~CloseURegion()~ */ static void CloseURegion(const ListExpr typeInfo, Word& w) { if (MRA_DEBUG) cerr << "CloseURegion() called" << endl; delete (URegion*) w.addr; w.addr = 0; } /* 1.1.1 Function ~CloneURegion()~ */ static Word CloneURegion(const ListExpr typeInfo, const Word& w) { if (MRA_DEBUG) cerr << "CloneURegion() called" << endl; return SetWord(((URegion*)w.addr)->Clone()); } /* 1.1.1 Function ~CastURegion()~ */ static void* CastURegion(void* addr) { if (MRA_DEBUG) cerr << "CastURegion() called" << endl; return new (addr) URegion; } /* 1.1.1 Function ~SizeOfURegion()~ */ static int SizeOfURegion() { if (MRA_DEBUG) cerr << "SizeOfURegion() called" << endl; return sizeof(URegion); } /* 1.1.1 Function ~OpenURegion()~ */ bool OpenURegion(SmiRecord& rec, size_t& offset, const ListExpr typeInfo, Word& w) { if (MRA_DEBUG) cerr << "OpenURegion() called" << endl; w = SetWord(Attribute::Open(rec, offset, typeInfo)); return true; } /* 1.1.1 Function ~SaveURegion()~ Makes sense on ~URegion~ instances with own segment storage only and will run into failed assertion for other instances. */ static bool SaveURegion(SmiRecord& rec, size_t& offset, const ListExpr typeInfo, Word& w) { if (MRA_DEBUG) cerr << "SaveURegion() called" << endl; URegion* ur = static_cast (w.addr); Attribute::Save(rec, offset, typeInfo, ur); return true; } /* 1.1.1 Type constructor ~uregion~ */ static TypeConstructor uregion( URegion::BasicType(), URegionProperty, OutURegion, InURegion, 0, 0, // SaveToList, RestoreFromList CreateURegion, DeleteURegion, OpenURegion, SaveURegion, CloseURegion, CloneURegion, CastURegion, SizeOfURegion, CheckURegion); /* 1 Data type ~mregion~ 1.1 Class ~MRegion~ 1.1.1 Class definition The class definition has been moved to ~MovingRegionAlgebra.h~. 1.1.1 Private methods 1.1.1.1 Method ~IntersectionRP()~ */ void MRegion::IntersectionRP( const MPoint& mp, MPoint& res, RefinementPartition< MRegion, MPoint, URegionEmb, UPoint>& rp, bool merge) { if (MRA_DEBUG) cerr << "MRegion::IntersectionRP() #1 called" << endl; res = MPoint(0); UPoint* pending = 0; /* For each interval in the refinement partition, we have to check whether it maps to a region and 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++) { Interval iv; int urPos; int upPos; rp.Get(i, iv, urPos, upPos); if (MRA_DEBUG) cerr << "MRegion::IntersectionRP() interval#" << i << ": " << iv.start.ToDouble() << " " << iv.end.ToDouble() << " " << iv.lc << " " << iv.rc << " " << urPos << " " << upPos << endl; if (urPos == -1 || upPos == -1) continue; URegionEmb ur; UPoint up; Get(urPos, ur); mp.Get(upPos, up); if (MRA_DEBUG) cerr << "MRegion::IntersectionRP() both elements present" << endl; ur.RestrictedIntersection( &msegmentdata, up, iv, res, pending, merge); } if (pending) { if (!(nearlyEqual(pending->timeInterval.start.ToDouble(), pending->timeInterval.end.ToDouble()) && (!pending->timeInterval.lc || !pending->timeInterval.rc))) { res.Add(*pending); } delete pending; } if (MRA_DEBUG) cerr << "MRegion::IntersectionRP() res.IsEmpty()=" << res.IsEmpty() << endl; } /* 1.1.1.1 Method ~InsideAddUBool()~ */ void MRegion::InsideAddUBool(MBool& res, Instant starttime, Instant endtime, bool lc, bool rc, bool value, Instant& prev, bool& prev_c, UBool*& pending) { if (MRA_DEBUG) cerr << "MRegion::InsideAddUBool() called, value=" << value << endl; Instant start(starttime); Instant end(endtime); CcBool bv(true, value); if (MRA_DEBUG) cerr << "MRegion::InsideAddUBool() adding " << setprecision(20) << start.ToString() << " (" << starttime.ToString() << ") " << end.ToString() << " (" << endtime << ") " << lc << " " << rc << endl; if (pending) { if (MRA_DEBUG) { cerr << "MRegion::InsideAddUBool() pending end=" << pending->timeInterval.end.ToString() << " rc=" << pending->timeInterval.rc << endl; cerr << "MRegion::InsideAddUBool() current start=" << start.ToString() << " lc=" << lc << endl; } if ((starttime == pending->timeInterval.end) && (pending->timeInterval.rc || lc) && pending->constValue.GetBoolval() == value) { if (MRA_DEBUG) cerr << "MRegion::InsideAddUBool() connecting" << endl; if (pending->timeInterval.start == pending->timeInterval.end) { Interval iv(start, end, true, rc); if (MRA_DEBUG) cerr << "MRegion::InsideAddUBool() connecting #1 to " << iv.start.ToString() << " " << iv.end.ToString() << " " << iv.lc << " " << iv.rc << endl; delete pending; pending = new UBool(iv, bv); } else if (starttime == endtime) { Interval iv(start, end, pending->timeInterval.lc, true); if (MRA_DEBUG) cerr << "MRegion::InsideAddUBool() connecting #2 to " << iv.start.ToString() << " " << iv.end.ToString() << " " << iv.lc << " " << iv.rc << endl; delete pending; pending = new UBool(iv, bv); } else { Interval iv(pending->timeInterval.start, end, pending->timeInterval.lc, rc); if (MRA_DEBUG) cerr << "MRegion::InsideAddUBool() connecting #3 to " << iv.start.ToString() << " " << iv.end.ToString() << " " << iv.lc << " " << iv.rc << endl; delete pending; pending = new UBool(iv, bv); } } else { if (MRA_DEBUG) cerr << "MRegion::InsideAddUBool() not connecting, pending is " << pending->timeInterval.start.ToString() << " " << pending->timeInterval.end.ToString() << " " << pending->timeInterval.lc << " " << pending->timeInterval.rc << endl; if(pending->IsValid()) res.Add(*pending); delete pending; Interval iv(start, end, lc, rc); pending = new UBool(iv, bv); } } else { if (MRA_DEBUG) cerr << "MRegion::InsideAddUBool() " << "pending does not exist" << endl; Interval iv(start, end, lc, rc); pending = new UBool(iv, bv); } prev = endtime; prev_c = rc; } Rectangle<3> MRegion::BoundingBox() const{ double min[] = {0.0,0.0,0.0}; double max[] = {1.0,1.0,1.0}; Rectangle<3> res(false, min,max ); // undefined or empty mregion if (!IsDefined() || GetNoComponents() < 1) { return res; } res.SetDefined(true); URegionEmb ur; Get(0, ur); res = ur.BoundingBox(); for(int i=1; i(n), msegmentdata(n) { if (MRA_DEBUG) cerr << "MRegion::MRegion(int) called" << endl; } //MRegion::MRegion(MPoint& mp, Region& r) : // original signature replaced with // 'call by copy' for 2nd arg due to problems when reading r // directly from disk ( raised assert( type == InMemory ) ): MRegion::MRegion(const MPoint& mp, const Region& _r) : Mapping(0), msegmentdata(0) { if (MRA_DEBUG) cerr << "MRegion::MRegion(MPoint, Region) called" << endl; if( !_r.IsDefined() || !mp.IsDefined() ){ del.isDefined=false; return; } Region* r = new Region(_r); r->LogicSort(); for (int i = 0; i < mp.GetNoComponents(); i++) { UPoint up; mp.Get(i, up); if (MRA_DEBUG) cerr << "MRegion::MRegion(MPoint, Region) i=" << i << " interval=[" << up.timeInterval.start.ToString() << " (" << up.timeInterval.start.ToDouble() << ") " << up.timeInterval.end.ToString() << "(" << up.timeInterval.end.ToDouble() << ") " << up.timeInterval.lc << " " << up.timeInterval.rc << "]" << endl; URegionEmb ur(&msegmentdata, up.timeInterval, *r, msegmentdata.Size()); if(ur.IsValid()) Add(ur); } del.isDefined=true; r->DeleteIfAllowed(); } MRegion::MRegion(const MPoint& mp, const Region& _r, const int dummy) : Mapping(0), msegmentdata(0) { if (MRA_DEBUG) cerr << "MRegion::MRegion(MPoint, Region,int) called" << endl; if( !_r.IsDefined() || !mp.IsDefined() ){ del.isDefined=false; return; } Region* r = new Region(_r); r->LogicSort(); bool isFirst = true; Coord lastX = 0.0, lastY = 0.0; Coord firstX = 0.0, firstY = 0.0; for (int i = 0; i < mp.GetNoComponents(); i++) { UPoint up; mp.Get(i, up); firstX = up.p0.GetX(); firstY = up.p0.GetY(); if( ! isFirst && (firstX !=lastX || firstY != lastY)){ r->Translate(firstX-lastX, firstY-lastY); }else{ isFirst=false; } lastX = up.p1.GetX(); lastY = up.p1.GetY(); URegionEmb ur(&msegmentdata, up.timeInterval, *r, msegmentdata.Size()); // now ur represents a static region // if this is not the case, we change the final line Coord tx = lastX-firstX; Coord ty = lastY-firstY; if(tx!=0 || ty!=0){ size_t usize = ur.GetSegmentsNum(); MSegmentData mseg; for(size_t i=0;i rbb(ur.BoundingBox()); double t[3]; t[0] = tx; t[1] = ty; t[2] = 0.0; rbb = rbb.Translate(t); ur.SetBBox(ur.BoundingBox().Union(rbb)); r->Translate(tx,ty); Add(ur); } del.isDefined=true; r->DeleteIfAllowed(); } /* 1.1.1 Attribute access methods 1.1.1.1 Method ~Get()~ */ void MRegion::Get(const int i, URegionEmb& ur) const { if (MRA_DEBUG) cerr << "MRegion::Get() #2 called i=" << i << " (msegmentdata=" << &msegmentdata << ")" << endl; Mapping::Get(i, ur); } /* 1.1.1.1 Method ~GetMSegmentData()~ */ const DbArray* MRegion::GetMSegmentData(void) { return &msegmentdata; } /* Add an idependent ~URegion~ object to the moving region. The URegions moving segment is copied to the DBArrays for ~msegmentdata~ and ~units~. */ void MRegion::AddURegion( URegion& U ) { #ifdef MR_DEBUG cout << "MRegion::AddURegion" << endl; U.Print(cout); #endif assert( IsDefined() ); if ( !U.IsDefined() || !IsDefined() ) return; URegionEmb tmp(true); int start=0, end=0; StartBulkLoad(); // copy adjusted U.uremb data to units start = msegmentdata.Size(); end = U.uremb.GetSegmentsNum(); tmp = *(U.GetEmbedded()); tmp.SetStartPos(start); Add(tmp); // append U.segments to msegmentdata for(int i=0 ; i rp(*this, mp); IntersectionRP(mp, res, rp, true); } /* 1.1.1.1 Method ~Inside()~ */ void MRegion::Inside(const MPoint& mp, MBool& res) { if (MRA_DEBUG) cerr << "MRegion::Inside() called" << endl; res.Clear(); if( !IsDefined() || !mp.IsDefined() ){ res.SetDefined( false ); return; } res.SetDefined( true ); /* Use intersection algorithm and then see how the units in the result match to the original units in ~mp~. First, we have to create the refinement partition for ~mp~ and this ~MRegion~ instance. */ RefinementPartition< MRegion, MPoint, URegionEmb, UPoint> rp(*this, mp); /* We are calling ~IntersectionRP()~ with value ~false~ for parameter ~merge~. This means that the resulting ~URegionEmb~ instances in ~resMp~ are not merged, ie. one ~URegionEmb~ instance's interval is entirely within one interval in ~rp~. */ MPoint resMp(0); IntersectionRP(mp, resMp, rp, false); int mpPos = 0; /* Required for ~InsideAddUBool()~. */ UBool* pending = 0; /* Pass through all the intervals in ~rp~. */ for (unsigned int rpPos = 0; rpPos < rp.Size(); rpPos++) { if (MRA_DEBUG) cerr << "MRegion::Inside() rpPos=" << rpPos << " mpPos=" << mpPos << endl; /* Get the units for each interval in ~rp~. */ Interval iv; int urPos; int upPos; rp.Get(rpPos, iv, urPos, upPos); /* We are only interested in the intervals, which are contained in ~mp~. If an interval in ~rp~ is not in ~mp~, ~upPos~ is lower than $0$ and we skip this interval. */ if (upPos < 0) continue; Instant prev = iv.start; bool prev_c = !iv.lc; /* Check every ~upoint~ instance in the intersection, which has an interval within the current interval. If we reach an instance outside the current interval, the ~for~ loop is left via a ~break~ statement. */ for (; mpPos < resMp.GetNoComponents(); mpPos++) { if (MRA_DEBUG) cerr << "MRegion::Inside() mpPos=" << mpPos << endl; /* Get the current ~upoint~ instance. */ UPoint up; resMp.Get(mpPos, up); if (MRA_DEBUG) cerr << "MRegion::Inside() rp iv=[" << iv.start.ToString() << " " << iv.end.ToString() << " " << iv.lc << " " << iv.rc << "] up iv=[" << up.timeInterval.start.ToString() << " " << up.timeInterval.end.ToString() << " " << up.timeInterval.lc << " " << up.timeInterval.rc << "]" << endl; /* Is this ~upoint~ instance really within the current interval? */ if (up.timeInterval.start.Compare(&iv.end) > 0 || (up.timeInterval.start.Compare(&iv.end) == 0 && up.timeInterval.lc && !iv.rc)) { /* No, we reached the end of the current interval. We add a ~ubool~ instance with value ~false~ to the result, which closes the gap between the previously added ~ubool~ instance and the end of the current interval (only if applicable). */ if (MRA_DEBUG) cerr << "MRegion::Inside() end of unit" << endl; if (prev.Compare(&iv.end) < 0) { if (MRA_DEBUG) cerr << "MRegion::Inside() closing gap #2a" << endl; InsideAddUBool(res, prev, iv.end, !prev_c, iv.rc, false, prev, prev_c, pending); } /* Break out of the loop iterating through the ~upoint~ instances in the intersection. */ break; } else { /* Yes, the current ~upoint~ instance is still within the current interval. */ if (MRA_DEBUG) cerr << "MRegion::Inside() inside unit" << endl; /* Is there a gap between the previously added ~ubool~ instance and the start of the interval of the current ~upoint~ instance? If so, close the gap by adding an ~ubool~ instance with an appropriate interval and value ~false~. */ if (up.timeInterval.start.Compare(&prev) > 0) { if (MRA_DEBUG) cerr << "MRegion::Inside() closing gap #1a, prev=" << setprecision(20) << prev << endl; InsideAddUBool(res, prev, up.timeInterval.start, !prev_c, !up.timeInterval.lc, false, prev, prev_c, pending); } else if (up.timeInterval.start.Compare(&prev) == 0 && !up.timeInterval.lc && prev_c) { if (MRA_DEBUG) cerr << "MRegion::Inside() closing gap #1b, prev=" << setprecision(15) << prev << endl; InsideAddUBool(res, up.timeInterval.start, up.timeInterval.start, true, true, false, prev, prev_c, pending); } /* Add a ~ubool~ instance with the interval of the current ~upoint~ instance and value ~true~. */ InsideAddUBool(res, up.timeInterval.start, up.timeInterval.end, up.timeInterval.lc, up.timeInterval.rc, true, prev, prev_c, pending); } } if (mpPos == resMp.GetNoComponents()) { if (MRA_DEBUG) cerr << "MRegion::Inside() end of units reached before" << endl; if (prev.Compare(&iv.end) < 0) { if (MRA_DEBUG) cerr << "MRegion::Inside() closing gap #3a" << endl; InsideAddUBool(res, prev, iv.end, !prev_c, iv.rc, false, prev, prev_c, pending); } else if (prev.Compare(&iv.end) == 0 && !prev_c && iv.rc) { if (MRA_DEBUG) cerr << "MRegion::Inside() closing gap #3b" << endl; InsideAddUBool(res, iv.end, iv.end, true, true, false, prev, prev_c, pending); } } } /* Since ~InsideAddUBool()~ is trying to merge adjacent ~ubool~ instances with identical value, there may be an ~ubool~ instance left in ~pending~, which needs to be added to the result. */ if (pending) { if (MRA_DEBUG) cerr << "MRegion::Inside() adding pending" << endl; if(pending->IsValid()) res.Add(*pending); delete pending; } } /* 1.1.1.1 Method ~AtInstant()~ Method ~Mapping::AtInstant()~ is not sufficient since it does not deal with setting the unit's segment data DBArray. */ void MRegion::AtInstant(const Instant& t, Intime& result) { if (MRA_DEBUG) cerr << "MRegion::AtInstant() called" << endl; assert(IsOrdered() && t.IsDefined()); int pos = Position(t ); if( pos == -1 ) result.SetDefined(false); else { URegionEmb posUnit; Get(pos, posUnit); result.SetDefined(true); posUnit.TemporalFunction(&msegmentdata, t, result.value); result.instant.CopyFrom(&t); } } /* 1.1.1.1 Method ~Initial()~ Method ~Mapping::Initial()~ is not sufficient since it does not deal with setting the unit's segment data DBArray. */ void MRegion::Initial(Intime& result) { if (MRA_DEBUG) cerr << "MRegion::Initial() called" << endl; if ( !IsDefined() || IsEmpty() ) { result.SetDefined(false); return; } result.SetDefined(true); assert(IsOrdered()); URegionEmb 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, unit.timeInterval.start, result.value); result.instant.CopyFrom(&unit.timeInterval.start); } /* 1.1.1.1 Method ~Final()~ Method ~Mapping::Final()~ is not sufficient since it does not deal with setting the unit's segment data DBArray. */ void MRegion::Final(Intime& result) { if (MRA_DEBUG) cerr << "MRegion::Final() called" << endl; if ( !IsDefined() || IsEmpty() ) { result.SetDefined(false); return; } result.SetDefined(true); assert(IsOrdered()); URegionEmb 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, unit.timeInterval.end, result.value); result.instant.CopyFrom(&unit.timeInterval.end); } /* 1.1.1.1 Method ~Traversed()~ */ #ifdef MRA_TRAVERSED void MRegion::Traversed(Region& res) { if (MRA_DEBUG) cerr << "MRegion::Traversed() called" << endl; /* Methods relating to operator ~traversed~ are currently being developed. In the meantime, we provide a stub with a failed assertion to recognize accidential calls of this method. */ cerr << "WARNING: Unimplemented function " << __PRETTY_FUNCTION__ << " called!" << endl; assert(false); res.Clear(); res.SetDefined( false ); } #endif // MRA_TRAVERSED /* 1.1.1 Methods for algebra integration 1.1.1.1 Method ~Clone()~ */ MRegion* MRegion::Clone(void) const { if (MRA_DEBUG) cerr << "MRegion::Clone() called" << endl; MRegion* res = new MRegion(0); res->CopyFrom(this); return res; } /* 1.1.1.1 Method ~CopyFrom()~ */ void MRegion::CopyFrom(const Attribute* right) { if (MRA_DEBUG) cerr << "MRegion::CopyFrom() called, this=" << this << ", &msegmentdata=" << &msegmentdata << endl; MRegion* mr = (MRegion*) right; Clear(); if( !mr->IsDefined() ){ SetDefined( false ); return; } SetDefined( true ); if (MRA_DEBUG) cerr << "MRegion::CopyFrom() called, &mr->msegmentdata=" << &mr->msegmentdata << endl; /* ~InMRegion()~ 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++) { URegionEmb ur; mr->Get(i, ur); Add(ur); } EndBulkLoad(false); /* Copy the moving segments. */ msegmentdata.clean(); if (mr->msegmentdata.Size() > 0) msegmentdata.resize(mr->msegmentdata.Size()); for (int i = 0; i < mr->msegmentdata.Size(); i++) { MSegmentData dms; mr->msegmentdata.Get(i, dms); if (MRA_DEBUG) cerr << "MRegion::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); } } /* 1.1.1.1 ~DBArray~ access */ int MRegion::NumOfFLOBs() const { if (MRA_DEBUG) cerr << "MRegion::NumOfFLOBs() called" << endl; return 2; } Flob* MRegion::GetFLOB(const int i) { if (MRA_DEBUG) cerr << "MRegion::GetFLOB() called" << endl; assert(i == 0 || i == 1); return i == 0 ? Mapping::GetFLOB(0) : &msegmentdata; } /* 1.1.1 Unit testing */ #ifdef MRA_UNITTEST bool MRegion::Unittest2(int pos) { if (MRA_DEBUG) cerr << "MRegion::Unittest2() called pos=" << pos << endl; if ( !IsDefined() || pos < 0 || pos >= msegmentdata.Size()) return -1; MSegmentData dms; msegmentdata.Get(pos, &dms); return dms.GetInsideAbove(); } #endif // MRA_UNITTEST /* 1.1 Algebra integration 1.1.1 Function ~MRegionProperty()~ */ static ListExpr MRegionProperty() { if (MRA_DEBUG) cerr << "MRegionProperty() called" << endl; ListExpr listrep = nl->TextAtom(); nl->AppendText(listrep, "(u1 ... un) with ui uregion list representations " "and n >= 1. Each ui is of format " "( *), where is " "( ) and where " " is ( *), " "where and are " "( ), representing " "start X, start Y, end X and end Y values."); ListExpr example = nl->TextAtom(); nl->AppendText(example, "(((0.0 10.0 TRUE TRUE)" "((((1.0 3.5 1.5 1.5)" "(2.0 5.5 3.0 4.5)" "(3.0 6.5 3.5 5.0)" "(4.0 6.5 5.5 5.0)" "(4.0 5.5 5.5 4.5)" "(5.0 4.5 7.5 2.5)" "(5.0 2.5 7.5 1.0)" "(4.0 1.5 7.0 0.5)" "(3.0 1.5 2.5 0.5))" "((2.0 3.0 3.0 2.0)" "(2.0 4.0 3.0 3.0)" "(3.0 4.0 4.0 3.0)" "(3.0 3.0 4.0 2.0))))))"); return nl->TwoElemList( nl->FourElemList( nl->StringAtom("Signature"), nl->StringAtom("Example Type List"), nl->StringAtom("List Rep"), nl->StringAtom("Example List")), nl->FourElemList( nl->StringAtom("-> MAPPING"), nl->StringAtom("(mregion)"), listrep, example)); } /* 1.1.1 Function ~CheckMRegion()~ */ static bool CheckMRegion(ListExpr type, ListExpr& errorInfo) { if (MRA_DEBUG) cerr << "CheckMRegion() called" << endl; return nl->IsEqual(type, MRegion::BasicType()) || nl->IsEqual(type, "movingregion"); } /* 1.1.1 Function ~OutMRegion()~ */ ListExpr OutMRegion(ListExpr typeInfo, Word value) { if (MRA_DEBUG) cerr << "OutMRegion() called" << endl; MRegion* mr = (MRegion*) value.addr; // check for undefined value if( !mr->IsDefined() ) return (nl->SymbolAtom(Symbol::UNDEFINED())); if (mr->IsEmpty()) return (nl->TheEmptyList()); assert(mr->IsOrdered()); ListExpr l = nl->TheEmptyList(); ListExpr lastElem = l; /* CD: lastElem was uninitialized */ if (MRA_DEBUG) cerr << "OutMRegion() #units=" << mr->GetNoComponents() << endl; for (int i = 0; i < mr->GetNoComponents(); i++) { if (MRA_DEBUG) cerr << "OutMRegion() i=" << i << endl; URegionEmb ur; mr->Get(i, ur); ListExpr unitList = OutURegionEmbedded( &ur, (DbArray*) mr->GetFLOB(1)); if (l == nl->TheEmptyList()) { l = nl->Cons(unitList, nl->TheEmptyList()); lastElem = l; } else lastElem = nl->Append(lastElem, unitList); } return l; } /* 1.1.1 Function ~InMRegion()~ */ Word InMRegion(const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct) { if (MRA_DEBUG) cerr << "InMRegion() called" << endl; MRegion* mr = new MRegion(0); if ( listutils::isSymbolUndefined( instance ) ) { mr->SetDefined(false); correct = true; return SetWord ( mr ); } mr->StartBulkLoad(); ListExpr rest = instance; while(!nl->IsEmpty(rest)) { ListExpr first = nl->First(rest); rest = nl->Rest(rest); URegionEmb* ur = (URegionEmb*) InURegionEmbedded( first, errorPos, errorInfo, &mr->msegmentdata, mr->msegmentdata.Size()); if (!ur) { correct = false; mr->Destroy(); delete mr; return SetWord(Address(0)); } mr->Add(*ur); delete ur; } mr->EndBulkLoad(true); if (mr->IsValid()) { correct = true; return SetWord(mr); } else { correct = false; mr->Destroy(); delete mr; return SetWord(Address(0)); } } /* 1.1.1 Function ~OpenMRegion()~ */ bool OpenMRegion(SmiRecord& rec, size_t& offset, const ListExpr typeInfo, Word& w) { if (MRA_DEBUG) cerr << "OpenMRegion() called" << endl; w = SetWord(Attribute::Open(rec, offset, typeInfo)); return true; } /* 1.1.1 Function ~SaveMRegion()~ */ static bool SaveMRegion(SmiRecord& rec, size_t& offset, const ListExpr typeInfo, Word& w) { if (MRA_DEBUG) cerr << "SaveMRegion() called" << endl; MRegion* mr = static_cast (w.addr); Attribute::Save(rec, offset, typeInfo, mr); return true; } /* 1.1.1 Type constructor ~mregion~ */ static Word CreateMRegion(const ListExpr typeInfo) { if (MRA_DEBUG) cerr << "CreateMRegion() called" << endl; return SetWord(new MRegion(0)); } static void DeleteMRegion(const ListExpr typeInfo, Word& w) { if (MRA_DEBUG) cerr << "DeleteMRegion() called" << endl; ((MRegion*) w.addr)->Destroy(); delete (MRegion*) w.addr; w.addr = 0; } static void CloseMRegion(const ListExpr typeInfo, Word& w) { if (MRA_DEBUG) cerr << "CloseMRegion() called" << endl; delete (MRegion*) w.addr; w.addr = 0; } static Word CloneMRegion(const ListExpr typeInfo, const Word& w) { if (MRA_DEBUG) cerr << "CloneMRegion() called" << endl; return SetWord(((MRegion*) w.addr)->Clone()); } static void* CastMRegion(void* addr) { if (MRA_DEBUG) cerr << "CastMRegion() called" << endl; return new (addr) MRegion; } static int SizeOfMRegion() { if (MRA_DEBUG) cerr << "SizeOfMRegion() called" << endl; int s = sizeof(MRegion); return s; } static TypeConstructor movingregion( MRegion::BasicType(), MRegionProperty, OutMRegion, InMRegion, 0, 0, // SaveToList, RestoreFromList CreateMRegion, DeleteMRegion, OpenMRegion, SaveMRegion, CloseMRegion, CloneMRegion, CastMRegion, SizeOfMRegion, CheckMRegion); /* 1.1 Helper function(s) Create ~MPoint~ instance from intervals in units in ~MRegion~ instance ~mr~ and the constant point ~p~. */ static MPoint CreateMPointFromPoint(MRegion* mr, Point* p) { if (MRA_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++) { URegionEmb ur; mr->Get(i, ur); UPoint up(ur.timeInterval, p->GetX(), p->GetY(), p->GetX(), p->GetY()); mp.Add(up); } } return mp; } /* 1 Operator definition 1.1 Type mapping functions 1.1.1 Generic Used by ~intersection~: */ static ListExpr MPointMRegionToMPointTypeMap(ListExpr args) { if (MRA_DEBUG) { cerr << "MPointMRegionToMPointTypeMap() 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), MRegion::BasicType())) return nl->SymbolAtom(MPoint::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~inside~: */ static ListExpr MPointMRegionToMBoolTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "MPointMRegionToMBoolTypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MPoint::BasicType()) && nl->IsEqual(nl->Second(args), MRegion::BasicType())) return nl->SymbolAtom(MBool::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~initial~ and ~final~: */ static ListExpr MRegionToIRegionTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "MRegionToIRegionTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), MRegion::BasicType())) return nl->SymbolAtom(IRegion::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~deftime~: */ static ListExpr MRegionToPeriodsTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "MRegionToPeriodsTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), MRegion::BasicType())) return nl->SymbolAtom(Range::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~inst~: */ static ListExpr IRegionToInstantTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "IRegionToInstantTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), IRegion::BasicType())) return nl->SymbolAtom(Instant::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~val~: */ static ListExpr IRegionToRegionTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "IRegionToRegionTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), IRegion::BasicType())) return nl->SymbolAtom(Region::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~traversed~: */ #ifdef MRA_TRAVERSED static ListExpr MRegionToRegionTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "MRegionToRegionTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), MRegion::BasicType())) return nl->SymbolAtom(Region::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } #endif // MRA_TRAVERSED /* 1.1.1 Operator specific Used by ~present~: */ static ListExpr PresentTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "PresentTypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MRegion::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()); } /* Used by ~at~: */ static ListExpr AtTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "AtTypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MPoint::BasicType()) && nl->IsEqual(nl->Second(args), Region::BasicType())) return nl->SymbolAtom(MPoint::BasicType()); else if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MRegion::BasicType()) && nl->IsEqual(nl->Second(args), Point::BasicType())) return nl->SymbolAtom(MPoint::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* used by addURegion */ ListExpr AddTypeMap( ListExpr args ) { if (MRA_DEBUG) cerr << "AddTypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MRegion::BasicType()) && nl->IsEqual(nl->Second(args), URegion::BasicType())) return nl->SymbolAtom(MRegion::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~union~: */ static ListExpr UnionTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "UnionTypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), URegion::BasicType()) && nl->IsEqual(nl->Second(args), URegion::BasicType())) return nl->SymbolAtom(URegion::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~atinstant~: */ static ListExpr AtInstantTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "AtInstantTypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MRegion::BasicType()) && nl->IsEqual(nl->Second(args), Instant::BasicType())) return nl->SymbolAtom(IRegion::BasicType()); else if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), URegion::BasicType()) && nl->IsEqual(nl->Second(args), Instant::BasicType())) return nl->SymbolAtom(IRegion::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~mraprec~: */ #ifdef MRA_PREC static ListExpr MraprecTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "MraprecTypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), CcReal::BasicType()) && nl->IsEqual(nl->Second(args), CcReal::BasicType())) return nl->SymbolAtom(CcBool::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } #endif // MRA_PREC /* Type mapping of the ~move~ operator: */ static ListExpr MoveTypeMap(ListExpr args){ if (MRA_DEBUG) cout << "MOveTypeMap called " << endl; if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("invalid number of arguments"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(!nl->IsEqual(nl->First(args),MPoint::BasicType())){ ErrorReporter::ReportError("mpoint as first argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(!nl->IsEqual(nl->Second(args),Region::BasicType())){ ErrorReporter::ReportError("region as second argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if (MRA_DEBUG) cout << "Typemap returns mregion" << endl; return nl->SymbolAtom(MRegion::BasicType()); } /* Used by ~bbox~: */ static ListExpr BboxTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "BboxTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), URegion::BasicType())) return nl->SymbolAtom(Rectangle<3>::BasicType()); if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), IRegion::BasicType())) return nl->SymbolAtom(Rectangle<3>::BasicType()); if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), MRegion::BasicType())) return nl->SymbolAtom(Rectangle<3>::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Used by ~bbox2d~: */ static ListExpr Bbox2dTypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "Bbox2dTypeMap() called" << endl; if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), URegion::BasicType())) return nl->SymbolAtom(Rectangle<2>::BasicType()); if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), IRegion::BasicType())) return nl->SymbolAtom(Rectangle<2>::BasicType()); if (nl->ListLength(args) == 1 && nl->IsEqual(nl->First(args), MRegion::BasicType())) return nl->SymbolAtom(Rectangle<2>::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Type mapping of the ~vertextrajectory~ operator: */ static ListExpr VertTrajectoryTypeMap(ListExpr args){ if(nl->ListLength(args)!=1){ ErrorReporter::ReportError("wrong number of arguments"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr arg = nl->First(args); if(nl->IsEqual(arg,URegion::BasicType()) || nl->IsEqual(arg,MRegion::BasicType())){ return nl->SymbolAtom(Line::BasicType()); } ErrorReporter::ReportError("uregion or mregion" " expected but got "); return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Type mapping for the ~units~ operator: */ ListExpr MRAUnitsTypeMap( ListExpr args ) { if ( nl->ListLength(args) == 1 ) { ListExpr arg1 = nl->First(args); if( nl->IsEqual( arg1, MRegion::BasicType() ) ) return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), nl->SymbolAtom(URegion::BasicType())); } return nl->SymbolAtom(Symbol::TYPEERROR()); } /* Type mapping for the ~timsshift~ operator: */ ListExpr MRegTimeShiftTM( ListExpr args ) { if ( nl->ListLength( args ) == 2 ) { ListExpr arg1 = nl->First( args ), arg2 = nl->Second( args ); if( nl->IsEqual( arg2, Duration::BasicType() ) ) { if( nl->IsEqual( arg1, MRegion::BasicType() ) ) return nl->SymbolAtom( MRegion::BasicType() ); } } return nl->SymbolAtom( Symbol::TYPEERROR() ); } /* 1.1.1 For unit testing operators */ #ifdef MRA_UNITTEST static ListExpr Unittest1TypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "Unittest1TypeMap() called" << endl; if (nl->ListLength(args) != 17) return nl->SymbolAtom(Symbol::TYPEERROR()); for (; !nl->IsEmpty(args); args = nl->Rest(args)) if (nl->SymbolValue(nl->First(args)) != CcReal::BasicType()) return nl->SymbolAtom(Symbol::TYPEERROR()); return nl->SymbolAtom(CcInt::BasicType()); } static ListExpr Unittest2TypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "Unittest2TypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MRegion::BasicType()) && nl->IsEqual(nl->Second(args), CcInt::BasicType())) return nl->SymbolAtom(CcBool::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } static ListExpr Unittest3TypeMap(ListExpr args) { if (MRA_DEBUG) cerr << "Unittest3TypeMap() called" << endl; if (nl->ListLength(args) == 2 && nl->IsEqual(nl->First(args), MPoint::BasicType()) && nl->IsEqual(nl->Second(args), MPoint::BasicType())) return nl->SymbolAtom(Range::BasicType()); else return nl->SymbolAtom(Symbol::TYPEERROR()); } #endif // MRA_UNITTEST /* 1.1 Selection functions 1.1.1 Generic Used by ~intersection~ and ~inside~: */ static int MPointMRegionSelect(ListExpr args) { if (MRA_DEBUG) cerr << "MPointMRegionSelect() called" << endl; if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MPoint::BasicType() && nl->SymbolValue(nl->Second(args)) == MRegion::BasicType()) return 0; else return -1; } /* Used by ~initial~, ~final~, ~deftime~ and ~traversed~: */ static int MRegionSelect(ListExpr args) { if (MRA_DEBUG) cerr << "MRegionSelect() called" << endl; if (nl->ListLength(args) == 1 && nl->SymbolValue(nl->First(args)) == MRegion::BasicType()) return 0; else return -1; } /* Used by ~inst~ and ~val~: */ static int IRegionSelect(ListExpr args) { if (MRA_DEBUG) cerr << "IRegionSelect() called" << endl; if (MRA_DEBUG) cerr << "IRegionSelect() len=" << nl->ListLength(args) << endl; if (MRA_DEBUG) cerr << "IRegionSelect() symbolvalue(first)=" << nl->SymbolValue(nl->First(args)) << endl; if (nl->ListLength(args) == 1 && nl->SymbolValue(nl->First(args)) == IRegion::BasicType()) return 0; else return -1; } /* 1.1.1 Operator specific For ~present~: */ static int PresentSelect(ListExpr args) { if (MRA_DEBUG) cerr << "PresentSelect() called" << endl; if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MRegion::BasicType() && nl->SymbolValue(nl->Second(args)) == Instant::BasicType()) return 0; else if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MRegion::BasicType() && nl->SymbolValue(nl->Second(args)) == Range::BasicType()) return 1; else return -1; } /* For ~at~: */ static int AtSelect(ListExpr args) { if (MRA_DEBUG) cerr << "AtSelect() called" << endl; if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MPoint::BasicType() && nl->SymbolValue(nl->Second(args)) == Region::BasicType()) return 0; else if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MRegion::BasicType() && nl->SymbolValue(nl->Second(args)) == Point::BasicType()) return 1; else return -1; } /* Used by ~atinstant~: */ static int AtInstantSelect(ListExpr args) { if (MRA_DEBUG) cerr << "AtInstantSelect() called" << endl; if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == MRegion::BasicType() && nl->SymbolValue(nl->Second(args)) == Instant::BasicType()) return 0; else if (nl->ListLength(args) == 2 && nl->SymbolValue(nl->First(args)) == URegion::BasicType() && nl->SymbolValue(nl->Second(args)) == Instant::BasicType()) return 1; else return -1; } /* Used by ~vertrajectory~: */ static int VertTrajectorySelect(ListExpr args){ ListExpr arg = nl->First(args); if(nl->IsEqual(arg,URegion::BasicType())) return 0; else return 1; } /* Used by ~bbox~ and ~bbox2d~: */ static int BBoxSelect(ListExpr args){ ListExpr arg = nl->First(args); if(nl->IsEqual(arg,URegion::BasicType())) return 0; if(nl->IsEqual(arg,IRegion::BasicType())) return 1; if(nl->IsEqual(arg,MRegion::BasicType())) return 2; else return -1; } /* 1.1 Value mapping functions 1.1.1 Normal value mapping functions */ static int IntersectionValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "IntersectionValueMap() called" << endl; result = qp->ResultStorage(s); MPoint* res = (MPoint*) result.addr; try { MPoint* mp = (MPoint*) args[0].addr; MRegion* mr = (MRegion*) 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 int InsideValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "InsideValueMap() called" << endl; result = qp->ResultStorage(s); MBool* res = (MBool*) result.addr; try { MPoint* mp = (MPoint*) args[0].addr; MRegion* mr = (MRegion*) 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; } // old implementation creates a MRegion: /* static int AtValueMap_MPointOld(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "AtValueMap_MPoint() called" << endl; result = qp->ResultStorage(s); MPoint* res = (MPoint*) result.addr; res->Clear(); res->SetDefined(true); try { MPoint* mp = (MPoint*) args[0].addr; Region* r = (Region*) args[1].addr; if (!mp->IsDefined() || !r->IsDefined()){ res->Clear(); res->SetDefined(false); } else { MRegion* mr = new MRegion(*mp, *r); mr->Intersection(*mp, *res); mr->DeleteIfAllowed(); } } catch (invalid_argument& e) { cerr << "-----------------------------------------------------------" << endl << "An error occured during the at operation:" << endl << e.what() << endl << "-----------------------------------------------------------" << endl; ((MPoint*) result.addr)->SetDefined(false); } return 0; } */ // new implementation calls specialized member of class MPoint: static int AtValueMap_MPoint(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << __PRETTY_FUNCTION__ << "(...) called" << endl; result = qp->ResultStorage(s); MPoint* res = static_cast(result.addr); res->Clear(); try { MPoint* mp = static_cast(args[0].addr); Region* r = static_cast(args[1].addr); mp->AtRegion(r, *res); } catch (invalid_argument& e) { cerr << "-----------------------------------------------------------" << endl << "An error occured during the at operation:" << endl << e.what() << endl << "-----------------------------------------------------------" << endl; res->SetDefined(false); } return 0; } static int AtValueMap_MRegion(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "AtValueMap_MRegion() called" << endl; result = qp->ResultStorage(s); MPoint* res = (MPoint*) result.addr; res->Clear(); res->SetDefined(true); try { MRegion* mr = (MRegion*) args[0].addr; Point* p = (Point*) args[1].addr; if (!mr->IsDefined() || !p->IsDefined()){ res->Clear(); res->SetDefined(false); } else { MPoint mp = CreateMPointFromPoint(mr, p); mr->Intersection(mp, *res); } } catch (invalid_argument& e) { cerr << "-----------------------------------------------------------" << endl << "An error occured during the at operation:" << endl << e.what() << endl << "-----------------------------------------------------------" << endl; ((MPoint*) result.addr)->SetDefined(false); } return 0; } static int AtInstantValueMap_URegion(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "AtInstantValueMap_URegion() called" << endl; result = qp->ResultStorage(s); Intime* res = (Intime*) result.addr; URegion* ur = (URegion*) args[0].addr; Instant* inst = (Instant*) args[1].addr; if (ur->IsDefined() && ur->timeInterval.Contains(*inst)) { ur->TemporalFunction(*inst, res->value); res->instant.CopyFrom(inst); res->SetDefined(true); } else { res->SetDefined(false); } return 0; } #ifdef MRA_TRAVERSED static int TraversedValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "TraversedValueMap() called" << endl; result = qp->ResultStorage(s); Region* res = (Region*) result.addr; MRegion* mr = (MRegion*) args[0].addr; if (!mr->IsDefined()) res->SetDefined(false); else mr->Traversed(*res); return 0; } #endif // MRA_TRAVERSED #ifdef MRA_PREC static int MraprecValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "MraprecValueMap() called" << endl; result = qp->ResultStorage(s); CcBool* res = (CcBool*) result.addr; CcReal* r1 = (CcReal*) args[0].addr; CcReal* r2 = (CcReal*) args[1].addr; if (!r1->IsDefined() || !r2->IsDefined()) res->SetDefined(false); else { eps = r1->GetRealval(); epsRelaxFactor = r2->GetRealval(); res->Set(true, true); } return 0; } #endif // MRA_PREC static int BboxValueMapURegion(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "BBox() called" << endl; result = qp->ResultStorage(s); Rectangle<3>* res = (Rectangle<3>*) result.addr; URegion* ur = (URegion*) args[0].addr; if (!ur->IsDefined()) res->SetDefined(false); else *res = ur->BoundingBox(); return (0); } static int BboxValueMapIRegion(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "BBox() called" << endl; result = qp->ResultStorage(s); Rectangle<3>* res = (Rectangle<3>*) result.addr; Intime* ur = (Intime*) args[0].addr; if (!ur->IsDefined()) res->SetDefined(false); else { Rectangle<2> r = ur->value.BoundingBox(); double min[3], max[3]; min[0] = r.MinD(0); min[1] = r.MinD(1); min[2] = ur->instant.ToDouble(); max[0] = r.MaxD(0); max[1] = r.MaxD(1); max[2] = min[2]; res->Set(true, min, max); } return (0); } static int BboxValueMapMRegion(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "BBox() called" << endl; result = qp->ResultStorage(s); Rectangle<3>* res = (Rectangle<3>*) result.addr; MRegion* mr = (MRegion*) args[0].addr; *res = mr->BoundingBox(); return (0); } static int Bbox2dValueMapURegion(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "BBox2d() called" << endl; result = qp->ResultStorage(s); Rectangle<2>* res = (Rectangle<2>*) result.addr; URegion* ur = (URegion*) args[0].addr; if (!ur->IsDefined()) res->SetDefined(false); else { Rectangle<3> bb3 = ur->BoundingBox(); double min[2] = {bb3.MinD(0), bb3.MinD(1)}; double max[2] = {bb3.MaxD(0), bb3.MaxD(1)}; res->Set( true, min, max ); } return (0); } static int Bbox2dValueMapIRegion(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "BBox2d() called" << endl; result = qp->ResultStorage(s); Rectangle<2>* res = (Rectangle<2>*) result.addr; Intime* ur = (Intime*) args[0].addr; if (!ur->IsDefined()) res->SetDefined(false); else { res->SetDefined(true); *res = ur->value.BoundingBox(); } return (0); } static int Bbox2dValueMapMRegion(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "BBox2d() called" << endl; result = qp->ResultStorage(s); Rectangle<2>* res = (Rectangle<2>*) result.addr; MRegion* mr = (MRegion*) args[0].addr; if (!mr->IsDefined() || (mr->GetNoComponents() < 1) ) res->SetDefined(false); else { res->SetDefined(true); URegionEmb ur; mr->Get(0, ur); Rectangle<3> bb3 = ur.BoundingBox(); for(int i=1; iGetNoComponents(); i++) { mr->Get(i, ur); bb3 = bb3.Union( ur.BoundingBox() ); } double min[2] = {bb3.MinD(0), bb3.MinD(1)}; double max[2] = {bb3.MaxD(0), bb3.MaxD(1)}; res->Set( true, min, max ); } return (0); } static int MoveValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); MPoint* mp = (MPoint* ) args[0].addr; Region* reg = (Region*) args[1].addr; MRegion res(*mp,*reg,0); ((MRegion*)result.addr)->CopyFrom(&res); res.Destroy(); return 0; } /* Value mapping functions of operator ~units~ */ struct MRAUnitsLocalInfo { Word mWord; // the address of the moving point/int/real value int unitIndex; // current item index }; int mraunitsvalmap(Word* args, Word& result, int message, Word& local, Supplier s) { MRegion* m; URegion* unit; MRAUnitsLocalInfo *localinfo; switch( message ) { case OPEN: m = static_cast(args[0].addr); if(m->IsDefined()){ localinfo = new MRAUnitsLocalInfo; localinfo->mWord = args[0]; localinfo->unitIndex = 0; local = SetWord(localinfo); } else { local.setAddr( 0 ); } return 0; case REQUEST: if( local.addr == 0 ) return CANCEL; localinfo = (MRAUnitsLocalInfo *) local.addr; m = (MRegion*)localinfo->mWord.addr; if( (0 <= localinfo->unitIndex) && (localinfo->unitIndex < m->GetNoComponents()) ) { unit = new URegion(localinfo->unitIndex++, *m); result = SetWord( unit ); return YIELD; } return CANCEL; case CLOSE: if( local.addr != 0 ) { delete (MRAUnitsLocalInfo *)local.addr; local = SetWord(Address(0)); } return 0; } // should not happen return -1; } /* Value mapping functions of operator ~timeshift~ */ int MRegTimeShiftMap( Word* args, Word& result, int message, Word& local, Supplier s ) { Word t; DateTime* dd; URegionEmb uregEmb; MRegion * mapping, *mpResult; result = qp->ResultStorage( s ); mapping= (MRegion*)args[0].addr, mpResult = (MRegion*)result.addr; mpResult->Clear(); dd = (DateTime *)args[1].addr; if( mapping->IsDefined() && dd->IsDefined() ) { mpResult->SetDefined( true ); if(mapping->GetNoComponents() == 0) return 0; mapping->Get(0, uregEmb); if( (uregEmb.timeInterval.start.ToDouble() + dd->ToDouble()) < 0 ) { mpResult->SetDefined( false ); return 0; } for( int i = 0; i < mapping->GetNoComponents(); i++ ) { URegion aux( i, *mapping ); aux.GetEmbedded()->timeInterval.start.Add(dd); aux.GetEmbedded()->timeInterval.end.Add(dd); mpResult->AddURegion(aux); } return 0; } else { mpResult->SetDefined( false ); return 0; } } /* 1.1.1 For unit testing operators */ #ifdef MRA_UNITTEST static int Unittest1ValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "Unittest1ValueMap() called" << endl; unsigned int detailedResult; for(int i=0; i<17; i++){ if( !(static_cast(args[i].addr))->IsDefined() ){ ((CcInt *)result.addr)->Set(false, -666); return 0; } } specialTrapeziumIntersects( ((CcReal*) args[0].addr)->GetRealval(), // dt ((CcReal*) args[1].addr)->GetRealval(), // t1p1x ((CcReal*) args[2].addr)->GetRealval(), // t1p1y ((CcReal*) args[3].addr)->GetRealval(), // t1p2x ((CcReal*) args[4].addr)->GetRealval(), // t1p2y ((CcReal*) args[5].addr)->GetRealval(), // t1p3x ((CcReal*) args[6].addr)->GetRealval(), // t1p3y ((CcReal*) args[7].addr)->GetRealval(), // t1p4x ((CcReal*) args[8].addr)->GetRealval(), // t1p4y ((CcReal*) args[9].addr)->GetRealval(), // t2p1x ((CcReal*) args[10].addr)->GetRealval(), // t2p1y ((CcReal*) args[11].addr)->GetRealval(), // t2p2x ((CcReal*) args[12].addr)->GetRealval(), // t2p2y ((CcReal*) args[13].addr)->GetRealval(), // t2p3x ((CcReal*) args[14].addr)->GetRealval(), // t2p3y ((CcReal*) args[15].addr)->GetRealval(), // t2p4x ((CcReal*) args[16].addr)->GetRealval(), // t2p4y detailedResult); if (MRA_DEBUG) cerr << "Unittest1ValueMap() #1" << endl; result = qp->ResultStorage(s); ((CcInt *)result.addr)->Set(true, detailedResult); if (MRA_DEBUG) cerr << "Unittest1ValueMap() #2" << endl; return 0; } static int Unittest2ValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "Unittest2ValueMap() called" << endl; result = qp->ResultStorage(s); MRegion* mr = static_cast(args[0].addr); CcInt* ci = static_cast(args[1].addr); if( mr->IsDefined() && ci->IsDefined() ){ ((CcBool *)result.addr)->Set( true, mr->Unittest2( ci->GetIntval()) ); } else { ((CcBool *)result.addr)->Set( false, false ); } return 0; } static int Unittest3ValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { if (MRA_DEBUG) cerr << "Unittest3ValueMap() called" << endl; result = qp->ResultStorage(s); RReal* res = (RReal *) result.addr; MPoint* mp1 = (MPoint*) args[0].addr; MPoint* mp2 = (MPoint*) args[1].addr; res->Clear(); if( !mp1->IsDefined() || !mp2->IsDefined() ){ res->SetDefined( false ); return 0; } res->SetDefined( true ); RefinementPartition rp(*mp1, *mp2); res->StartBulkLoad(); for (unsigned int i = 0; i < rp.Size(); i++) { Interval iv; int urPos; int upPos; rp.Get(i, iv, urPos, upPos); CcReal left(true, iv.start.ToDouble()); CcReal right(true, iv.end.ToDouble()); Interval resIv(left, right, iv.lc, iv.rc); res->Add(resIv); } res->EndBulkLoad(true); return 0; } #endif // MRA_UNITTEST template static int VertTrajectory_ValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); T* ur = (T*) args[0].addr; const DbArray* segments = ur->GetMSegmentData(); int size = segments->Size(); Line* L = (Line*) result.addr; L->Clear(); if( !ur->IsDefined() ){ L->SetDefined( false ); return 0; } L->SetDefined( true ); L->StartBulkLoad(); MSegmentData mseg; cout << " insert " << size << " segments" << endl; HalfSegment hs; int edgeno = 0; for(int i=0;iGet(i,&mseg); Point P1(true,mseg.GetInitialStartX(),mseg.GetInitialStartY()); Point P2(true,mseg.GetFinalStartX(),mseg.GetFinalStartY()); hs.Set(true,P1,P2); hs.attr.edgeno = edgeno++; //cout << "insert " << hs << "to the line" << endl; (*L)+=hs; hs.SetLeftDomPoint(!hs.IsLeftDomPoint()); (*L)+=hs; } L->EndBulkLoad(); return 0; } static int addvaluemap(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); MRegion* mreg1 = (MRegion* ) args[0].addr; URegion* ureg1 = (URegion*) args[1].addr; MRegion* res = static_cast(result.addr); res->Clear(); if( !mreg1->IsDefined() || !ureg1->IsDefined() ){ res->SetDefined( false ); return 0; } res->SetDefined( true ); bool disj=true; for(int i=0;iGetNoComponents();i++) { URegionEmb ur; mreg1->Get(i,ur); if(!ureg1->timeInterval.Disjoint(ur.timeInterval)) { disj=false; } } if(disj) { res->CopyFrom(mreg1); res->AddURegion(*ureg1); } else { res->SetDefined(false); cerr<<"Error, Intervals are not disjoint"<ResultStorage(s); URegion* reg1 = static_cast(args[0].addr); URegion* reg2 = static_cast(args[1].addr); URegion* res = static_cast(result.addr); if( !reg1->IsDefined() || !reg2->IsDefined() ){ res->SetDefined( false ); return 0; } try { res->CopyFrom(reg1); res->AddURegion(reg2); } catch (invalid_argument& e) { res->SetDefined( false ); cerr<, AtInstantValueMap_URegion }; static ValueMapping initialvaluemap[] = { MappingInitial }; static ValueMapping finalvaluemap[] = { MappingFinal }; static ValueMapping instvaluemap[] = { IntimeInst }; static ValueMapping valvaluemap[] = { IntimeVal }; static ValueMapping deftimevaluemap[] = { MappingDefTime }; static ValueMapping presentvaluemap[] = { MappingPresent_i, MappingPresent_p }; static ValueMapping intersectionvaluemap[] = { IntersectionValueMap }; static ValueMapping insidevaluemap[] = { InsideValueMap }; static ValueMapping atvaluemap[] = { AtValueMap_MPoint, AtValueMap_MRegion }; static ValueMapping verttrajectoryvaluemap[] = { VertTrajectory_ValueMap, VertTrajectory_ValueMap}; #ifdef MRA_TRAVERSED static ValueMapping traversedvaluemap[] = { TraversedValueMap }; #endif // MRA_TRAVERSED static ValueMapping BboxValueMap[] = { BboxValueMapURegion, BboxValueMapIRegion, BboxValueMapMRegion }; static ValueMapping Bbox2dValueMap[] = { Bbox2dValueMapURegion, Bbox2dValueMapIRegion, Bbox2dValueMapMRegion }; /* 1.1 Operator specifications */ static const string atinstantspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (mregion instant) -> iregion, " " (uregion instant) -> iregion," " _ atinstant _ " " Get the iregion value corresponding " "to the instant." " mregion1 atinstant instant1 ) )"; static const string initialspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion -> iregion" " initial( _ )" " Get the iregion value corresponding to " "the initial instant." " " " initial( mregion1 ) ) )"; static const string finalspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion -> iregion" " final( _ )" " Get the iregion value corresponding to " "the final instant." " " " final( mregion1 ) ) )"; static const string instspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( iregion -> instant" " inst ( _ )" " iregion time instant." " inst ( iregion1 ) ) )"; static const string valspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( iregion -> region" " val ( _ )" " Intime value." " val ( iregion1 ) ) )"; static const string deftimespec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion -> periods" " deftime( _ )" " Get the defined time of the mregion object." " deftime( mregion1 ) ) )"; static const string presentspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (mregion instant) -> bool, " "(mregion periods) -> bool" " _ present _ " " Whether the object is present at the given instant or" " period." " mregion1 present instant1 ) )"; static const string intersectionspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (mpoint mregion) -> mpoint" " intersection( _ , _ )" " Intersection between mpoint and mregion." " intersection(mpoint1, mregion1) ) )"; static const string insidespec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (mpoint mregion) -> mbool" " _ inside _" " Calculates if and when mpoint is inside " "mregion." " mpoint1 inside mregion1 ) )"; static const string atspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (mpoint region) -> mpoint, " "(mregion point) -> mpoint" " _ at _" " Restrict moving point to region or restrict moving region " "to point." " mpoint1 at region1 ) )"; static const string addspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (mregion uregion) -> mregion" " adduregion(_, _)" " Add a uregion to a mregion," "if all the periods are disjoint." " query adduregion( msnow ,interpolate(thecenter, " "thecenter translate[100.0, -1000.0], theRange(theInstant(2003, 11, 20, 9)," "theInstant(2003, 11, 20, 11), TRUE, FALSE))) ) )"; static const string unionspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (uregion uregion) -> uregion " " _ union _" " Calculate a URegion by adding one URegion to another." "Works only, if the periods are equal" " uregion1 unit uregion2 ) )"; static const string movespec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mpoint x region -> mregion" " move( _ , _)" " Creates a moving region from the given region" " using the mpoint speed and direction " " query move(mp,reg) ) )"; #ifdef MRA_TRAVERSED static const string traversedspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion -> region" " traversed( _ )" " Projection of a moving region into " "the plane." " traversed(mregion1) ) )"; #endif // MRA_TRAVERSED #ifdef MRA_PREC static const string mraprecspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (real) -> bool" " mraprec( _ , _ )" " Sets precision of comparisons. Two floating point values " "are considered equal by the algebra, if their difference is lower " "or equal than the first parameter. The second parameter specifies " "a relaxed comparison precision for the check whether a moving " "segment is collinear with itself in its the initial and final " "instant. In this case, two floating point values are considered " "equal if their difference is lower or equal than the first " "parameter times the second parameter. The operator " "always returns true." " mraprec(0.0001, 10) ) )"; #endif // MRA_PREC static const string bboxspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( uregion -> rect3,\n" "iregion -> rect3, \n" "mregion -> rect3" " bbox( _ )" " Returns the 3d bounding box of the spatio-temporal " "value." " bbox(mregion1) ) )"; static const string bbox2dspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( uregion -> rect,\n" "iregion -> rect, \n" "mregion -> rect" " bbox2d( _ )" " Returns the 2d bounding box of the " "spatio-temporal value." " bbox2d(mregion1) ) )"; static const string verttrajectoryspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( (uregion || mregion) -> line" " vertextrajectory( _ )" " Computes the trajectory of the vertices " " vertextrajectory(mregion1) ) )"; const string mraunitsspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( mregion -> (stream uregion)" "units( _ )" "Create the stream of all uregions contained by " "the moving region." "units( mregion1 )) )"; const string MRegTimeShiftSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( mregion x duration -> mregion" "_ timeshift[ _ ]" "Shifts the definition time of the moving region object." "msnow timeshift[ create_duration(1, 0) ]" ") )"; /* Used for unit testing only. */ #ifdef MRA_UNITTEST static const string unittestspec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " " ( unit testing only" " unit testing only" " unit testing only" " unit testing only ) )"; #endif // MRA_UNITTEST /* 1.1 Operator creation */ namespace movingregionops{ static Operator atinstant("atinstant", atinstantspec, 2, atinstantvaluemap, AtInstantSelect, AtInstantTypeMap); static Operator initial("initial", initialspec, 1, initialvaluemap, MRegionSelect, MRegionToIRegionTypeMap); static Operator final("final", finalspec, 1, finalvaluemap, MRegionSelect, MRegionToIRegionTypeMap); static Operator inst("inst", instspec, 1, instvaluemap, IRegionSelect, IRegionToInstantTypeMap); static Operator val("val", valspec, 1, valvaluemap, IRegionSelect, IRegionToRegionTypeMap); static Operator deftime("deftime", deftimespec, 1, deftimevaluemap, MRegionSelect, MRegionToPeriodsTypeMap); static Operator present("present", presentspec, 2, presentvaluemap, PresentSelect, PresentTypeMap); static Operator intersection("intersection", intersectionspec, 1, intersectionvaluemap, MPointMRegionSelect, MPointMRegionToMPointTypeMap); static Operator inside("inside", insidespec, 1, insidevaluemap, MPointMRegionSelect, MPointMRegionToMBoolTypeMap); static Operator at("at", atspec, 2, atvaluemap, AtSelect, AtTypeMap); static Operator addURegion("adduregion", addspec, addvaluemap, Operator::SimpleSelect, AddTypeMap); static Operator Union("union", unionspec, unionvaluemap, Operator::SimpleSelect, UnionTypeMap); #ifdef MRA_TRAVERSED static Operator traversed("traversed", traversedspec, 1, traversedvaluemap, MRegionSelect, MRegionToRegionTypeMap); #endif // MRA_TRAVERSED #ifdef MRA_PREC static Operator mraprec("mraprec", mraprecspec, MraprecValueMap, simpleSelect, MraprecTypeMap); #endif // MRA_PREC static Operator bbox("bbox", bboxspec, 3, BboxValueMap, BBoxSelect, BboxTypeMap); static Operator bbox2d("bbox2d", bbox2dspec, 3, Bbox2dValueMap, BBoxSelect, Bbox2dTypeMap); static Operator move("move", movespec, MoveValueMap, simpleSelect, MoveTypeMap); static Operator vertextrajectory("vertextrajectory", verttrajectoryspec, 2, verttrajectoryvaluemap, VertTrajectorySelect, VertTrajectoryTypeMap); static Operator mraunits("units", mraunitsspec, mraunitsvalmap, Operator::SimpleSelect, MRAUnitsTypeMap); Operator mregtimeshift( "timeshift", MRegTimeShiftSpec, MRegTimeShiftMap, Operator::SimpleSelect, MRegTimeShiftTM ); /* Used for unit testing only. */ #ifdef MRA_UNITTEST static Operator unittest1("unittest1", unittestspec, Unittest1ValueMap, simpleSelect, Unittest1TypeMap); static Operator unittest2("unittest2", unittestspec, Unittest2ValueMap, simpleSelect, Unittest2TypeMap); static Operator unittest3("unittest3", unittestspec, Unittest3ValueMap, simpleSelect, Unittest3TypeMap); #endif // MRA_UNITTEST } // end of namespace movingregionops /* 1 Algebra creation */ class MovingRegionAlgebra : public Algebra { public: MovingRegionAlgebra() : Algebra() { AddTypeConstructor(&intimeregion); AddTypeConstructor(&uregion); AddTypeConstructor(&movingregion); intimeregion.AssociateKind(Kind::TEMPORAL()); intimeregion.AssociateKind(Kind::DATA()); uregion.AssociateKind(Kind::TEMPORAL()); uregion.AssociateKind(Kind::SPATIAL3D()); uregion.AssociateKind(Kind::DATA()); movingregion.AssociateKind(Kind::TEMPORAL()); movingregion.AssociateKind(Kind::DATA()); AddOperator(&movingregionops::atinstant); AddOperator(&movingregionops::initial); AddOperator(&movingregionops::final); AddOperator(&movingregionops::inst); AddOperator(&movingregionops::val); AddOperator(&movingregionops::deftime); AddOperator(&movingregionops::present); AddOperator(&movingregionops::intersection); AddOperator(&movingregionops::inside); AddOperator(&movingregionops::at); AddOperator(&movingregionops::addURegion); AddOperator(&movingregionops::Union); AddOperator(&movingregionops::bbox); AddOperator(&movingregionops::bbox2d); AddOperator(&movingregionops::move); AddOperator(&movingregionops::vertextrajectory); AddOperator(&movingregionops::mraunits); AddOperator(&movingregionops::mregtimeshift); #ifdef MRA_TRAVERSED AddOperator(&movingregionops::traversed); #endif // MRA_TRAVERSED #ifdef MRA_PREC AddOperator(&movingregionops::mraprec); #endif // MRA_PREC /* Used for unit testing only. */ #ifdef MRA_UNITTEST AddOperator(&movingregionops::unittest1); AddOperator(&movingregionops::unittest2); AddOperator(&movingregionops::unittest3); #endif // MRA_UNITTEST } ~MovingRegionAlgebra() {} }; } // end of namespace temporalalgebra extern "C" Algebra* InitializeMovingRegionAlgebra(NestedList* nlRef, QueryProcessor *qpRef) { nl = nlRef; qp = qpRef; return new temporalalgebra::MovingRegionAlgebra(); }