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

5022 lines
128 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2013, University in Hagen,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
//[_] [\_]
[1] Implementation of the Region2Algebra
September 2013, first implementation by Oliver Feuer for bachelor thesis
[TOC]
1 Overview
This implementation file contains the implementation of the classes ~Reg2PreciseHalfSegment~
and ~Region2~. The class ~Region2~ correspond to the memory representation for the type
constructor ~regionp~.
2 Defines and Includes
*/
#include "Region2Algebra.h"
using namespace std;
/*
1 Helper functions
1.1 ~reverseCycle2~
Changes the direction of a cycle.
*/
void reverseCycle2(vector<Reg2PrecisePoint>& cycle){
for (unsigned int i=0; i < cycle.size()/2; i++)
{
Reg2PrecisePoint tmp = cycle[i];
cycle[i] = cycle[cycle.size()-(i+1)];
cycle[cycle.size()-(i+1)] = tmp;
}
}
/*
1.1 ~getDir2~
Determines the direction of a cycle. If the cycle is in clockwise order, the
return value is true. If the cycle is directed counter clockwise, the result will
be false.
*/
bool getDir2(const vector<Reg2PrecisePoint>& vp)
{
// determine the direction of cycle
int min = 0;
for (unsigned int i=1; i < vp.size(); i++)
{
if (vp[i] < vp[min]) {
min = i;
}
}
bool cw;
int s = vp.size();
if ( vp[0] == vp[vp.size()-1] )
{
s--;
}
Reg2PrecisePoint a = vp[ (min - 1 + s ) % s ];
Reg2PrecisePoint p = vp[min];
Reg2PrecisePoint b = vp[ (min+1) % s];
if ( cmp(a.x, p.x) == 0 ) // a -> p vertical
{
if ( cmp(a.y, p.y) > 0 )
{
cw = false;
}
else
{
cw = true;
}
}
else if ( cmp(p.x, b.x) == 0 ) //p -> b vertical
{
if ( cmp(p.y, b.y) > 0 )
{
cw = false;
}
else
{
cw = true;
}
}
else // both segments are non-vertical
{
mpq_class m_p_a = (a.y-p.y) / (a.x-p.x);
m_p_a.canonicalize();
mpq_class m_p_b = (b.y-p.y) / (b.x-p.x);
m_p_b.canonicalize();
if ( cmp(m_p_a, m_p_b) > 0 )
{
cw = false;
}
else
{
cw = true;
}
}
return cw;
}
/*
1.1 ~buildRegion2~
Builds a ~Region2~ from a vector of cycles which is a vector of precise points
using the bulk load of class ~Region2~.
*/
Region2* buildRegion2(const int scale,
vector< vector<Reg2PrecisePoint> >& cycles)
{
if (cycles.size() < 1)
{
cerr << "no face found within the cycles" << endl;
return (new Region2(0));
}
multiset<Reg2PreciseHalfSegment> multiHSSet;
list<Reg2PreciseHalfSegment> multiHSList;
int e = 0;
for (unsigned int i = 0; i < cycles.size(); i++)
{
vector<Reg2PrecisePoint> cycle = cycles[i];
bool cw = getDir2(cycle);
for (unsigned int j=0; j < cycle.size()-1; j++)
{
Reg2PrecisePoint lp,rp;
bool small = cycle[j] < cycle[j+1];
if (small)
{
lp = cycle[j];
rp = cycle[j+1];
}
else
{
lp = cycle[j+1];
rp = cycle[j];
}
Reg2PreciseHalfSegment hs(true,lp,rp);
hs.attr.edgeno = e++;
hs.attr.insideAbove = (cw && !small) || (!cw && small);
hs.attr.insideAbove = !small;
hs.attr.faceno=0;
hs.attr.cycleno = 0;
hs.attr.coverageno = 0;
multiHSSet.insert(hs);
}
}
Region2* reg = new Region2(0);
reg->SetScaleFactor(scale, false);
reg->StartBulkLoad();
while (!multiHSSet.empty())
{
Reg2PreciseHalfSegment hs(*multiHSSet.begin());
multiHSSet.erase(multiHSSet.begin());
Reg2PreciseHalfSegment hs2(hs);
hs2.SetLeftDomPoint(false);
*reg += hs;
*reg += hs2;
multiHSList.push_back(hs);
}
reg->EndBulkLoad();
if (!reg->validateRegion2() )
{
delete reg;
reg = 0;
}
return reg;
}
/*
1.1 output operators
*/
ostream& operator<<( ostream& o, const Reg2GridPoint& p )
{
if( p.IsDefined() )
o << "(" << p.x << ", " << p.y << ")";
else
o << Symbol::UNDEFINED();
return o;
}
ostream& operator<<( ostream& o, const Reg2PrecisePoint& p )
{
if( p.IsDefined() )
o << "(" << p.x << ", " << p.y << ")";
else
o << Symbol::UNDEFINED();
return o;
}
ostream& operator<<(ostream &os, const Reg2GridHalfSegment& hs)
{
return os << "("
<<"F("<< hs.attr.faceno
<<") C("<< hs.attr.cycleno
<<") E(" << hs.attr.edgeno<<") DP("
<< (hs.IsLeftDomPoint()? "L":"R")
<<") IA("<< (hs.attr.insideAbove? "A":"U")
<<") Co("<<hs.attr.coverageno
<<") PNo("<<hs.attr.partnerno
<<") (("<< hs.GetLeftPointX() << ", "
<< hs.GetLeftPointY()
<< ") ("<< hs.GetRightPointX() << ", "
<< hs.GetRightPointY()
<<")) ";
}
ostream& operator<<(ostream &os, const Reg2PrecHalfSegment& hs)
{
return os << "lx " << hs.getlxNumPosition() << " "
<< hs.getlxDenPosition()
<< " " << hs.getlxNumInts() << " " << hs.getlxDenInts()
<< ", ly " << hs.getlyNumPosition() << " "
<< hs.getlyDenPosition()
<< " " << hs.getlyNumInts() << " " << hs.getlyDenInts()
<< ", rx " << hs.getrxNumPosition() << " "
<< hs.getrxDenPosition()
<< " " << hs.getrxNumInts() << " " << hs.getrxDenInts()
<< ", ry " << hs.getryNumPosition() << " "
<< hs.getryDenPosition()
<< " " << hs.getryNumInts() << " " << hs.getryDenInts();
}
ostream& operator<<(ostream &os, const Reg2PreciseHalfSegment& hs)
{
return os << "("
<<"F("<< hs.attr.faceno
<<") C("<< hs.attr.cycleno
<<") E(" << hs.attr.edgeno<<") DP("
<< (hs.IsLeftDomPoint()? "L":"R")
<<") IA("<< (hs.attr.insideAbove? "A":"U")
<<") Co("<<hs.attr.coverageno
<<") PNo("<<hs.attr.partnerno
<<") ("<< hs.GetLeftPoint() << " "
<< hs.GetRightPoint() <<") ";
}
/*
1 Functions of Reg2PreciseHalfSegment
1.1 Function ~Intersects~
*/
bool Reg2PreciseHalfSegment::Intersects(
const Reg2PreciseHalfSegment& hs ) const
{
mpq_class k(0), a(0), K(0), A(0);
if ( !BoundingBox().Intersects( hs.BoundingBox() ) )
return false;
Reg2PrecisePoint hs_lp = hs.GetLeftPoint(),
hs_rp = hs.GetRightPoint();
if ( cmp(lp.x, rp.x) == 0 &&
cmp(hs_lp.x, hs_rp.x) == 0 )
// both segments are vertical
{
if ( cmp(lp.x, hs_lp.x) == 0 &&
(( cmp(hs_lp.y, lp.y)<=0 && cmp(lp.y, hs_rp.y)<=0 ) ||
( cmp(hs_lp.y, rp.y)<=0 && cmp(rp.y, hs_rp.y)<=0 ) ||
( cmp(lp.y, hs_lp.y)<=0 && cmp(hs_lp.y, rp.y)<=0 ) ||
( cmp(lp.y, hs_rp.y)<=0 && cmp(hs_rp.y, rp.y)<=0 )) )
return true;
return false;
}
if ( cmp(lp.x, rp.x) != 0 )
// this segment is not vertical
{
k = (rp.y - lp.y) / (rp.x - lp.x);
k.canonicalize();
a = lp.y - k * lp.x;
a.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) != 0 )
// hs is not vertical
{
K = (hs_rp.y - hs_lp.y) / (hs_rp.x - hs_lp.x);
K.canonicalize();
A = hs_lp.y - K * hs_lp.x;
A.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) == 0 )
//only hs is vertical
{
mpq_class y0 = k * hs_lp.x + a;
y0.canonicalize();
if ( cmp(lp.x, hs_lp.x) <= 0 &&
cmp(hs_lp.x, rp.x) <= 0 )
{
if ( (cmp(hs_lp.y, y0) <= 0 &&
cmp(y0, hs_rp.y) <= 0 ) ||
(cmp(hs_rp.y, y0) <= 0 &&
cmp(y0, hs_lp.y) <= 0 ) )
// (Xl, y0) is the intersection point
return true;
}
return false;
}
if ( cmp(lp.x, rp.x) == 0 )
// only this segment is vertical
{
mpq_class Y0 = K * lp.x + A;
Y0.canonicalize();
if ( cmp(hs_lp.x, lp.x) <= 0 &&
cmp(lp.x, hs_rp.x) <= 0 )
{
if ( (cmp(lp.y, Y0) <= 0 &&
cmp(Y0, rp.y) <= 0 ) ||
(cmp(rp.y, Y0) <= 0 &&
cmp(Y0, lp.y) <= 0 ) )
// (xl, Y0) is the intersection point
return true;
}
return false;
}
// both segments are non-vertical
if ( cmp(k, K) == 0 )
// both segments have the same inclination
{
if ( cmp(A, a) == 0 &&
(( cmp(hs_lp.x, lp.x) <= 0 &&
cmp(lp.x, hs_rp.x) <= 0 ) ||
( cmp(lp.x, hs_lp.x) <= 0 &&
cmp(hs_lp.x, rp.x) <= 0 )) )
// the segments are in the same straight line
return true;
}
else
{
mpq_class x0 = (A - a) / (k - K);
x0.canonicalize();
// y0 = x0 * k + a;
if( cmp(lp.x, x0) <= 0 &&
cmp(x0, rp.x) <= 0 &&
cmp(hs_lp.x, x0) <= 0 &&
cmp(x0, hs_rp.x) <= 0 )
// the segments intersect at (x0, y0)
return true;
}
return false;
}
/*
1.1 Function ~InnerIntersects~
*/
bool Reg2PreciseHalfSegment::InnerIntersects(
const Reg2PreciseHalfSegment& hs ) const
{
mpq_class k(0), a(0), K(0), A(0);
if ( !BoundingBox().Intersects( hs.BoundingBox() ) )
return false;
Reg2PrecisePoint hs_lp = hs.GetLeftPoint(),
hs_rp = hs.GetRightPoint();
if ( cmp(lp.x, rp.x) == 0 &&
cmp(hs_lp.x, hs_rp.x) == 0 )
// both segments are vertical
{
if ( cmp(lp.x, hs_lp.x) != 0 )
return false;
mpq_class ylow, yup, hs_ylow, hs_yup;
if ( cmp(lp.y, rp.y) < 0 )
{
ylow = lp.y;
yup = rp.y;
}
else
{
ylow = rp.y;
yup = lp.y;
}
if ( cmp(hs_lp.y, hs_rp.y) < 0 )
{
hs_ylow = hs_lp.y;
hs_yup = hs_rp.y;
}
else
{
hs_ylow = hs_rp.y;
hs_yup = hs_lp.y;
}
if( ylow >= hs_yup || yup <= hs_ylow )
return false;
return true;
}
if ( cmp(lp.x, rp.x) != 0 )
// this segment is not vertical
{
k = (rp.y - lp.y) / (rp.x - lp.x);
k.canonicalize();
a = lp.y - k * lp.x;
a.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) != 0 )
// hs is not vertical
{
K = (hs_rp.y - hs_lp.y) / (hs_rp.x - hs_lp.x);
K.canonicalize();
A = hs_lp.y - K * hs_lp.x;
A.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) == 0 )
//only hs is vertical
{
mpq_class y0 = k * hs_lp.x + a;
y0.canonicalize();
if ( cmp(lp.x, hs_lp.x) <= 0 &&
cmp(hs_lp.x, rp.x) <= 0 )
{
if ( (cmp(hs_lp.y, y0) < 0 &&
cmp(y0, hs_rp.y) < 0 ) ||
(cmp(hs_rp.y, y0) < 0 &&
cmp(y0, hs_lp.y) < 0 ) )
// (Xl, y0) is the intersection point
return true;
}
return false;
}
if ( cmp(lp.x, rp.x) == 0 )
// only this segment is vertical
{
mpq_class Y0 = K * lp.x + A;
Y0.canonicalize();
if ( cmp(hs_lp.x, lp.x) < 0 &&
cmp(lp.x, hs_rp.x) < 0 )
{
if ( (cmp(lp.y, Y0) <= 0 &&
cmp(Y0, rp.y) <= 0 ) ||
(cmp(rp.y, Y0) <= 0 &&
cmp(Y0, lp.y) <= 0 ) )
// (xl, Y0) is the intersection point
return true;
}
return false;
}
// both segments are non-vertical
if ( cmp(k, K) == 0 )
// both segments have the same inclination
{
if ( cmp(A, a) != 0 ) //Parallel lines
return false;
//they are in the same straight line
if ( cmp(rp.x, hs_lp.x) <= 0 ||
cmp(hs_rp.x, lp.x) <= 0 )
return false;
return true;
}
else
{
mpq_class x0 = (A - a) / (k - K);
x0.canonicalize();
// y0 = x0 * k + a;
if( cmp(lp.x, x0) <= 0 &&
cmp(x0, rp.x) <= 0 &&
cmp(hs_lp.x, x0) <= 0 &&
cmp(x0, hs_rp.x) <= 0 )
// the segments intersect at (x0, y0)
return true;
}
return false;
}
/*
1.1 Function ~Crosses~
*/
bool Reg2PreciseHalfSegment::Crosses(
const Reg2PreciseHalfSegment& hs ) const
{
mpq_class k(0), a(0), K(0), A(0);
if ( !BoundingBox().Intersects( hs.BoundingBox() ) )
return false;
Reg2PrecisePoint hs_lp = hs.GetLeftPoint(),
hs_rp = hs.GetRightPoint();
if ( cmp(lp.x, rp.x) == 0 &&
cmp(hs_lp.x, hs_rp.x) == 0 )
// both segments are vertical
return false;
if ( cmp(lp.x, rp.x) != 0 )
// this segment is not vertical
{
k = (rp.y - lp.y) / (rp.x - lp.x);
k.canonicalize();
a = lp.y - k * lp.x;
a.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) != 0 )
// hs is not vertical
{
K = (hs_rp.y - hs_lp.y) / (hs_rp.x - hs_lp.x);
K.canonicalize();
A = hs_lp.y - K * hs_lp.x;
A.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) == 0 )
//only hs is vertical
{
mpq_class y0 = k * hs_lp.x + a;
y0.canonicalize();
if ( cmp(lp.x, hs_lp.x) < 0 &&
cmp(hs_lp.x, rp.x) < 0 )
{
if ( (cmp(hs_lp.y, y0) < 0 &&
cmp(y0, hs_rp.y) < 0 ) ||
(cmp(hs_rp.y, y0) < 0 &&
cmp(y0, hs_lp.y) < 0 ) )
// (Xl, y0) is the intersection point
return true;
}
return false;
}
if ( cmp(lp.x, rp.x) == 0 )
// only this segment is vertical
{
mpq_class Y0 = K * lp.x + A;
Y0.canonicalize();
if ( cmp(hs_lp.x, lp.x) < 0 &&
cmp(lp.x, hs_rp.x) < 0 )
{
if ( (cmp(lp.y, Y0) < 0 &&
cmp(Y0, rp.y) < 0 ) ||
(cmp(rp.y, Y0) < 0 &&
cmp(Y0, lp.y) < 0 ) )
// (xl, Y0) is the intersection point
return true;
}
return false;
}
// both segments are non-vertical
if ( cmp(k, K) == 0 )
// both segments have the same inclination
{
return false;
}
else
{
mpq_class x0 = (A - a) / (k - K);
x0.canonicalize();
// y0 = x0 * k + a;
if( cmp(lp.x, x0) < 0 &&
cmp(x0, rp.x) < 0 &&
cmp(hs_lp.x, x0) < 0 &&
cmp(x0, hs_rp.x) < 0 )
// the segments intersect at (x0, y0)
return true;
}
return false;
}
/*
1.1 Function ~Intersection~
*/
bool Reg2PreciseHalfSegment::Intersection(
const Reg2PreciseHalfSegment& hs,
Reg2PrecisePoint& resp ) const
{
mpq_class k(0), a(0), K(0), A(0);
if ( !BoundingBox().Intersects( hs.BoundingBox() ) )
return false;
Reg2PrecisePoint hs_lp = hs.GetLeftPoint(),
hs_rp = hs.GetRightPoint();
resp.SetDefined( true );
// Check for same endpoints
if ( lp == hs_lp )
{
if ( !hs.Contains(rp) && !this->Contains(hs_rp) )
{
resp = lp;
return true;
} else {
return false; //overlapping halfsegments
}
}
else if ( rp == hs_lp )
{
if (!hs.Contains(lp) && !this->Contains(hs_rp) ) {
resp = rp;
return true;
} else {
return false; //overlapping halfsegments
}
}
else if ( lp == hs_rp )
{
if ( !hs.Contains(rp) && !this->Contains(hs_lp) ) {
resp = lp;
return true;
} else {
return false; //overlapping halfsegments
}
}
else if ( rp == hs_rp )
{
if (!hs.Contains(lp) && !this->Contains(hs_lp)){
resp = rp;
return true;
} else {
return false; //overlapping halfsegments
}
}
if ( cmp(lp.x, rp.x) == 0 &&
cmp(hs_lp.x, hs_rp.x) == 0 )
// both segments are vertical
{
if ( cmp(hs_lp.y, rp.y) == 0 ) {
resp.Set(rp.x, rp.y);
return true;
}
if ( cmp(lp.y, hs_rp.y) == 0 ) {
resp.Set( lp.x, lp.y );
return true;
}
return false;
}
if ( cmp(lp.x, rp.x) != 0 )
// this segment is not vertical
{
k = (rp.y - lp.y) / (rp.x - lp.x);
k.canonicalize();
a = lp.y - k * lp.x;
a.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) != 0 )
// hs is not vertical
{
K = (hs_rp.y - hs_lp.y) / (hs_rp.x - hs_lp.x);
K.canonicalize();
A = hs_lp.y - K * hs_lp.x;
A.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) == 0 )
//only hs is vertical
{
mpq_class y0 = k * hs_lp.x + a;
y0.canonicalize();
if ( cmp(lp.x, hs_lp.x) <= 0 &&
cmp(hs_lp.x, rp.x) <= 0 )
{
if ( (cmp(hs_lp.y, y0) <= 0 &&
cmp(y0, hs_rp.y) <= 0 ) ||
(cmp(hs_rp.y, y0) <= 0 &&
cmp(y0, hs_lp.y) <= 0 ) ) {
// (Xl, y0) is the intersection point
resp.Set(hs_lp.x, y0);
return true;
}
}
return false;
}
if ( cmp(lp.x, rp.x) == 0 )
// only this segment is vertical
{
mpq_class Y0 = K * lp.x + A;
Y0.canonicalize();
if ( cmp(hs_lp.x, lp.x) <= 0 &&
cmp(lp.x, hs_rp.x) <= 0 )
{
if ( (cmp(lp.y, Y0) <= 0 &&
cmp(Y0, rp.y) <= 0 ) ||
(cmp(rp.y, Y0) <= 0 &&
cmp(Y0, lp.y) <= 0 ) ) {
// (xl, Y0) is the intersection point
resp.Set(lp.x, Y0);
return true;
}
}
return false;
}
if ( cmp(k, K) == 0 )
// both segments have the same inclination
{
if ( rp == hs.lp ) {
resp = rp;
return true;
}
if ( lp == hs.rp ) {
resp = lp;
return true;
}
return false;
}
else
{
mpq_class x0 = (A - a) / (k - K);
x0.canonicalize();
mpq_class y0 = x0 * k + a;
y0.canonicalize();
if ( cmp(lp.x, x0) <= 0 &&
cmp(x0, rp.x) <= 0 &&
cmp(hs_lp.x, x0) <= 0 &&
cmp(x0, hs_rp.x) <= 0 ) {
// the segments intersect at (x0, y0)
resp.Set( x0, y0 );
return true;
}
}
return false;
}
/*
1.1 Function ~Intersection~
*/
bool Reg2PreciseHalfSegment::Intersection(
const Reg2PreciseHalfSegment& hs,
Reg2PreciseHalfSegment& reshs ) const
{
mpq_class k(0), a(0), K(0), A(0);
if ( !BoundingBox().Intersects( hs.BoundingBox() ) )
return false;
if ( *this == hs )
{
reshs = hs;
return true;
}
Reg2PrecisePoint hs_lp = hs.GetLeftPoint(),
hs_rp = hs.GetRightPoint();
if ( cmp(lp.x, rp.x) == 0 &&
cmp(hs_lp.x, hs_rp.x) == 0 )
// both segments are vertical
{
mpq_class ylow, yup, hs_ylow, hs_yup;
if ( cmp(lp.y, rp.y) < 0 )
{
ylow = lp.y;
yup = rp.y;
}
else
{
ylow = rp.y;
yup = lp.y;
}
if ( cmp(hs_lp.y, hs_rp.y) < 0 )
{
hs_ylow = hs_lp.y;
hs_yup = hs_rp.y;
}
else
{
hs_ylow = hs_rp.y;
hs_yup = hs_lp.y;
}
if ( cmp(hs_ylow, yup) < 0 && cmp(ylow, hs_yup) < 0 )
{
Reg2PrecisePoint p1, p2;
if ( cmp(ylow, hs_ylow) > 0 )
p1.Set( lp.x, ylow );
else
p1.Set( lp.x, hs_ylow );
if ( cmp(yup, hs_yup) < 0 )
p2.Set( lp.x, yup );
else
p2.Set( lp.x, hs_yup );
reshs.Set( true, p1, p2 );
return true;
}
else return false;
}
if ( cmp(lp.x, rp.x) == 0 ||
cmp(hs_lp.x, hs_rp.x) == 0 )
// one of the segments is vertical
return false;
if ( cmp(lp.x, rp.x) != 0 )
// this segment is not vertical
{
k = (rp.y - lp.y) / (rp.x - lp.x);
k.canonicalize();
a = lp.y - k * lp.x;
a.canonicalize();
}
if ( cmp(hs_lp.x, hs_rp.x) != 0 )
// hs is not vertical
{
K = (hs_rp.y - hs_lp.y) / (hs_rp.x - hs_lp.x);
K.canonicalize();
A = hs_lp.y - K * hs_lp.x;
A.canonicalize();
}
if ( cmp(k, K) == 0 && cmp(a, A) == 0 )
{
if ( cmp(rp.x, hs_lp.x) > 0 && cmp(lp.x, hs_rp.x) < 0 )
{
Reg2PrecisePoint p1, p2;
if ( cmp(lp.x, hs_lp.x) > 0 )
p1.Set( lp.x, lp.y );
else
p1.Set( hs_lp.x, hs_lp.y );
if ( cmp(rp.x, hs_rp.x) < 0 )
p2.Set( rp.x, rp.y );
else
p2.Set( hs_rp.x, hs_rp.y );
reshs.Set( true, p1, p2 );
return true;
}
}
return false;
}
/*
1.1 Function ~Inside~
*/
bool Reg2PreciseHalfSegment::Inside(
const Reg2PreciseHalfSegment& hs ) const
{
return hs.Contains( GetLeftPoint() ) &&
hs.Contains( GetRightPoint() );
}
/*
1.1 Function ~RayAbove~
*/
bool Reg2PreciseHalfSegment::RayAbove(
const Reg2PrecisePoint& p, mpq_class &yIntersection ) const
{
assert(p.IsDefined());
if (this->IsVertical())
return false;
mpq_class xl = GetLeftPoint().x,
yl = GetLeftPoint().y,
xr = GetRightPoint().x,
yr = GetRightPoint().y;
if ( cmp(xl, p.x) == 0 && cmp(p.y, yl) < 0 )
{
yIntersection = yl;
return true;
}
else if ( cmp(xl, p.x) < 0 && cmp(p.x, xr) <= 0 )
{
mpq_class k = (yr - yl) / (xr - xl);
k.canonicalize();
mpq_class a = (yl - k * xl);
a.canonicalize();
mpq_class y0 = k * p.x + a;
y0.canonicalize();
if (cmp(y0, p.y) > 0)
{
yIntersection = y0;
return true;
}
}
return false;
}
/*
1.1 Function ~RayDown~
*/
bool Reg2PreciseHalfSegment::RayDown(
const Reg2PrecisePoint& p, mpq_class &yIntersection ) const
{
assert(p.IsDefined());
if (this->IsVertical())
return false;
mpq_class xl = GetLeftPoint().x,
yl = GetLeftPoint().y,
xr = GetRightPoint().x,
yr = GetRightPoint().y;
// between is true, iff xl <= x <= xr.
const bool between = cmp(xl, p.x) <= 0 && cmp(p.x, xr) <= 0;
if (!between)
return false;
mpq_class k = (yr - yl) / (xr - xl);
k.canonicalize();
mpq_class a = (yl - k * xl);
a.canonicalize();
mpq_class y0 = k * p.x + a;
y0.canonicalize();
if (cmp(y0, p.y) > 0) // y0 > y: this is above p.
return false;
// y0 <= p: p is above or on this.
yIntersection = y0;
return true;
}
/*
1 Region2 class
1.1 Copy-Constructor ~Region2~
*/
Region2::Region2( const Region2& cr, bool onlyLeft ) :
StandardSpatialAttribute<2>( cr.IsDefined() ),
scaleFactor( cr.scaleFactor ),
gridCoordinates( cr.Size() ),
precCoordinates( cr.Size() ),
preciseCoordinates( 0 ),
bbox( cr.bbox ),
noComponents( cr.noComponents ),
ordered( true ),
maxIntx(cr.maxIntx),
maxInty(cr.maxInty),
minIntx(cr.minIntx),
minInty(cr.minInty),
maxPrecx(0),
maxPrecy(0),
minPrecx(0),
minPrecy(0)
{
if( IsDefined() && cr.Size() > 0 )
{
assert( cr.IsOrdered() );
if( !onlyLeft )
{
gridCoordinates.copyFrom(cr.gridCoordinates);
precCoordinates.copyFrom(cr.precCoordinates);
preciseCoordinates.copyFrom(cr.preciseCoordinates);
precHSvector = cr.precHSvector;
}
else
{
StartBulkLoad();
Reg2PreciseHalfSegment hs;
for( int i = 0; i < cr.Size(); i++ )
{
cr.Get( i, hs );
if ( hs.IsLeftDomPoint() )
precHSvector.push_back(hs);
}
EndBulkLoad( false, false, false, false, false );
}
}
}
/*
1.1 Constructor ~Region2~ from a ~region~ object
*/
Region2::Region2( const Region& r, const int sFactor ) :
StandardSpatialAttribute<2>(r.IsDefined()),
scaleFactor( sFactor ),
gridCoordinates(0),
precCoordinates(0),
preciseCoordinates(0)
{
Clear();
if( r.IsDefined() )
{
SetDefined( true);
HalfSegment hs;
Reg2PreciseHalfSegment phs;
StartBulkLoad();
int e = 0;
for( int i = 0; i < r.Size(); i++ )
{
r.Get( i, hs );
if (hs.IsLeftDomPoint())
{
phs = Reg2PreciseHalfSegment(hs);
if ( overflowAsInt(phs.GetLeftPoint().x,
phs.GetLeftPoint().y, sFactor)
|| overflowAsInt(phs.GetRightPoint().x,
phs.GetRightPoint().y, sFactor) )
{
if (sFactor != 0)
cerr << "Integer Overflow - scale factor " << sFactor
<< " is too big!";
else
cerr << "Integer Overflow - please use a scale factor!";
cerr << endl;
Clear();
SetDefined( false );
return;
}
phs.attr.edgeno = e++;
*this += phs;
phs.SetLeftDomPoint(false);
*this += phs;
}
}
EndBulkLoad();
}
else {
SetDefined( false );
}
}
/*
1.1 Constructor ~Region2~ from a ~rect2~ object
*/
Region2::Region2( const Rectangle<2>& r, const int sFactor ) :
StandardSpatialAttribute<2>(r.IsDefined()),
scaleFactor( sFactor ),
gridCoordinates(0),
precCoordinates(0),
preciseCoordinates(0)
{
Clear();
if( r.IsDefined() )
{
SetDefined( true);
Reg2PreciseHalfSegment hs;
int partnerno = 0;
mpq_class min0(r.MinD(0));
mpq_class max0(r.MaxD(0));
mpq_class min1(r.MinD(1));
mpq_class max1(r.MaxD(1));
Reg2PrecisePoint v1(max0, min1);
Reg2PrecisePoint v2(max0, max1);
Reg2PrecisePoint v3(min0, max1);
Reg2PrecisePoint v4(min0, min1);
if ( v1 == v2 || v2 == v3 || v3 == v4 || v4 == v1 )
{ // one interval is (almost) empty, so will be the region
SetDefined( true );
return;
}
if ( overflowAsInt(v1.x, v1.y, sFactor)
|| overflowAsInt(v2.x, v2.y, sFactor)
|| overflowAsInt(v3.x, v3.y, sFactor)
|| overflowAsInt(v4.x, v4.y, sFactor) )
{
if (sFactor != 0)
cerr << "Integer Overflow - scale factor " << sFactor
<< " is too big!";
else
cerr << "Integer Overflow - please use a scale factor!";
cerr << endl;
Clear();
SetDefined( false );
return;
}
SetDefined( true );
StartBulkLoad();
hs = Reg2PreciseHalfSegment(true, v1, v2);
hs.attr.faceno = 0; // only one face
hs.attr.cycleno = 0; // only one cycle
hs.attr.edgeno = partnerno;
hs.attr.partnerno = partnerno++;
hs.attr.insideAbove = (hs.GetLeftPoint() == v1);
*this += hs;
hs.SetLeftDomPoint( !hs.IsLeftDomPoint() );
*this += hs;
hs = Reg2PreciseHalfSegment(true, v2, v3);
hs.attr.faceno = 0; // only one face
hs.attr.cycleno = 0; // only one cycle
hs.attr.edgeno = partnerno;
hs.attr.partnerno = partnerno++;
hs.attr.insideAbove = (hs.GetLeftPoint() == v2);
*this += hs;
hs.SetLeftDomPoint( !hs.IsLeftDomPoint() );
*this += hs;
hs = Reg2PreciseHalfSegment(true, v3, v4);
hs.attr.faceno = 0; // only one face
hs.attr.cycleno = 0; // only one cycle
hs.attr.edgeno = partnerno;
hs.attr.partnerno = partnerno++;
hs.attr.insideAbove = (hs.GetLeftPoint() == v3);
*this += hs;
hs.SetLeftDomPoint( !hs.IsLeftDomPoint() );
*this += hs;
hs = Reg2PreciseHalfSegment(true, v4, v1);
hs.attr.faceno = 0; // only one face
hs.attr.cycleno = 0; // only one cycle
hs.attr.edgeno = partnerno;
hs.attr.partnerno = partnerno++;
hs.attr.insideAbove = (hs.GetLeftPoint() == v4);
*this += hs;
hs.SetLeftDomPoint( !hs.IsLeftDomPoint() );
*this += hs;
EndBulkLoad();
}
else {
SetDefined( false );
}
}
/*
1.1 Function ~Get~
*/
bool Region2::Get(const unsigned int i, Reg2PreciseHalfSegment& hs) const
{
if (i < 0 || i >= (unsigned int)Size())
return false;
else if (precHSvector.size() == 0)
{
Reg2GridHalfSegment gHS;
Reg2PrecHalfSegment pHS;
gridCoordinates.Get(i, gHS);
precCoordinates.Get(i, pHS);
mpz_t sFactor;
mpz_init(sFactor);
mpq_class sFac(0);
uint sfactor;
if (scaleFactor < 0)
{
sfactor = -scaleFactor;
mpz_ui_pow_ui(sFactor, 10, sfactor);
sFac = mpq_class(mpz_class(sFactor), mpz_class(1));
}
else
{
sfactor = scaleFactor;
mpz_ui_pow_ui(sFactor, 10, sfactor);
sFac = mpq_class(mpz_class(1), mpz_class(sFactor));
}
sFac.canonicalize();
mpz_clear(sFactor);
mpq_class lx = (pHS.GetlPointx(&preciseCoordinates)
+ gHS.GetLeftPointX()) * sFac;
lx.canonicalize();
mpq_class ly = (pHS.GetlPointy(&preciseCoordinates)
+ gHS.GetLeftPointY()) * sFac;
ly.canonicalize();
mpq_class rx = (pHS.GetrPointx(&preciseCoordinates)
+ gHS.GetRightPointX()) * sFac;
rx.canonicalize();
mpq_class ry = (pHS.GetrPointy(&preciseCoordinates)
+ gHS.GetRightPointY()) * sFac;
ry.canonicalize();
Reg2PrecisePoint pl = Reg2PrecisePoint(lx, ly);
Reg2PrecisePoint pr = Reg2PrecisePoint(rx, ry);
hs = Reg2PreciseHalfSegment(gHS.IsLeftDomPoint(), pl, pr);
AttrType attr = AttrType(gHS.GetAttr());
hs.SetAttr(attr);
return true;
}
else if (i >= 0 && i < precHSvector.size())
{
hs = precHSvector[i];
return true;
}
else
return false;
}
/*
1.1 Function ~StartBulkLoad~
*/
void Region2::StartBulkLoad()
{
ordered = false;
}
/*
1.1 Function ~EndBulkLoad~
*/
void Region2::EndBulkLoad( bool sortit, bool setCoverageNo,
bool setPartnerNo, bool computeRegion,
bool buildDb )
{
if( !IsDefined() ) {
Clear();
return;
}
if ( sortit )
sort(precHSvector.begin(), precHSvector.end());
if ( setCoverageNo )
{
int currCoverageNo = 0;
Reg2PreciseHalfSegment hs;
for(unsigned int i= 0; i< precHSvector.size(); i++ )
{
hs = precHSvector[i];
if ( hs.IsLeftDomPoint() )
currCoverageNo++;
else
currCoverageNo--;
precHSvector[i].attr.coverageno = currCoverageNo;
}
}
if ( setPartnerNo )
SetPartnerNo();
if ( computeRegion )
ComputeRegion();
if ( buildDb )
buildDbArrays();
ordered = true;
}
/*
1.1 Function ~Contains~
*/
bool Region2::Contains( const Reg2PrecisePoint& p) const
{
assert( IsDefined() );
assert( p.IsDefined() );
if ( IsEmpty() || !p.IsDefined() )
{
return false;
}
if ( !p.Inside(bbox) )
{
return false;
}
assert( IsOrdered() );
map<int, int> faceISN;
Reg2PreciseHalfSegment hs;
int coverno=0;
unsigned int startpos=0;
mpq_class y0;
//1. find the right place
for (startpos = 0; startpos < precHSvector.size()
&& p >= precHSvector[startpos].GetDomPoint() ; startpos++)
if ( precHSvector[startpos].GetDomPoint() == p )
return true;
if ( startpos == 0 ){ //p is smallest
return false;
} else if ( startpos == precHSvector.size() ){ //p is largest
return false;
}
int i = startpos - 1;
//2. deal with equal-x hs's
hs = precHSvector[i];
while( i > 0 &&
cmp(hs.GetDomPoint().x, p.x) == 0 ){
if( hs.Contains(p) )
{
return true;
}
if( hs.IsLeftDomPoint() && hs.RayAbove( p, y0 ) ){
if( faceISN.find( hs.attr.faceno ) != faceISN.end() ){
faceISN[ hs.attr.faceno ]++;
} else {
faceISN[ hs.attr.faceno ] = 1;
}
}
hs = precHSvector[--i];
}
// at this point, i is pointing to the last hs whose dp.x != p.x
//3. get the coverage value
coverno = hs.attr.coverageno;
//4. search the region value for coverageno steps
int touchedNo = 0;
while( i >= 0 && touchedNo < coverno ){
hs = precHSvector[i];
if( hs.Contains(p) ){
return true;
}
if( hs.IsLeftDomPoint() &&
cmp(hs.GetLeftPoint().x, p.x) <= 0 &&
cmp(p.x, hs.GetRightPoint().x) <= 0 )
{
touchedNo++;
}
if( hs.IsLeftDomPoint() && hs.RayAbove( p, y0 ) ){
if( faceISN.find( hs.attr.faceno ) != faceISN.end() ){
faceISN[ hs.attr.faceno ]++;
} else {
faceISN[ hs.attr.faceno ] = 1;
}
}
i--; //the iterator
}
for( map<int, int>::iterator iter = faceISN.begin();
iter != faceISN.end();
iter++ ){
if( iter->second % 2 != 0 ){
return true;
}
}
return false;
}
/*
1.1 Function ~InnerContains~
*/
bool Region2::InnerContains( const Reg2PrecisePoint& p) const
{
assert( IsDefined() );
assert( p.IsDefined() );
if ( IsEmpty() || !p.IsDefined() )
{
return false;
}
if ( !p.Inside(bbox) )
{
return false;
}
assert( IsOrdered() );
map<int, int> faceISN;
Reg2PreciseHalfSegment hs;
int coverno=0;
unsigned int startpos=0;
mpq_class y0;
//1. find the right place
for (startpos = 0; startpos < precHSvector.size()
&& p >= precHSvector[startpos].GetDomPoint() ; startpos++)
if ( precHSvector[startpos].GetDomPoint() == p )
return false;
if ( startpos == 0 ){ //p is smallest
return false;
} else if ( startpos == precHSvector.size() ){ //p is largest
return false;
}
int i = startpos - 1;
//2. deal with equal-x hs's
hs = precHSvector[i];
while( i > 0 &&
cmp(hs.GetDomPoint().x, p.x) == 0 ){
if( hs.Contains(p) )
{
return false;
}
if( hs.IsLeftDomPoint() && hs.RayAbove( p, y0 ) ){
if( faceISN.find( hs.attr.faceno ) != faceISN.end() ){
faceISN[ hs.attr.faceno ]++;
} else {
faceISN[ hs.attr.faceno ] = 1;
}
}
hs = precHSvector[--i];
}
// at this point, i is pointing to the last hs whose dp.x != p.x
//3. get the coverage value
coverno = hs.attr.coverageno;
//4. search the region value for coverageno steps
int touchedNo = 0;
while( i >= 0 && touchedNo < coverno ){
hs = precHSvector[i];
if( hs.Contains(p) ){
return false;
}
if( hs.IsLeftDomPoint() &&
cmp(hs.GetLeftPoint().x, p.x) <= 0 &&
cmp(p.x, hs.GetRightPoint().x) <= 0 )
{
touchedNo++;
}
if( hs.IsLeftDomPoint() && hs.RayAbove( p, y0 ) ){
if( faceISN.find( hs.attr.faceno ) != faceISN.end() ){
faceISN[ hs.attr.faceno ]++;
} else {
faceISN[ hs.attr.faceno ] = 1;
}
}
i--; //the iterator
}
for( map<int, int>::iterator iter = faceISN.begin();
iter != faceISN.end();
iter++ ){
if( iter->second % 2 != 0 ){
return true;
}
}
return false;
}
/*
1.1 Function ~Contains~
*/
bool Region2::Contains( const Reg2PreciseHalfSegment& hs) const
{
assert( IsDefined() );
if ( IsEmpty() )
{
return false;
}
if ( !hs.GetLeftPoint().Inside(bbox) ||
!hs.GetRightPoint().Inside(bbox) )
{
return false;
}
if ( !Contains(hs.GetLeftPoint()) ||
!Contains(hs.GetRightPoint()) )
{
return false;
}
Reg2PreciseHalfSegment auxhs;
//now we know that both endpoints of hs is inside region
for( unsigned int i = 0; i < precHSvector.size(); i++ )
{
auxhs = precHSvector[i];
if( auxhs.IsLeftDomPoint() ){
if( hs.Crosses(auxhs) ){
return false;
} else if( hs.Inside(auxhs) ) { //hs is part of the border
return true;
}
}
}
return true;
}
/*
1.1 Function ~InnerContains~
*/
bool Region2::InnerContains( const Reg2PreciseHalfSegment& hs) const
{
assert( IsDefined() );
if( IsEmpty() ){
return false;
}
if( !hs.GetLeftPoint().Inside(bbox) ||
!hs.GetRightPoint().Inside(bbox) ){
return false;
}
if( !InnerContains(hs.GetLeftPoint()) ||
!InnerContains(hs.GetRightPoint()) ){
return false;
}
Reg2PreciseHalfSegment auxhs;
//now we know that both endpoints of hs are
//completely inside the region
for( int i = 0; i < Size(); i++ ){
auxhs = precHSvector[i];
if( auxhs.IsLeftDomPoint() ){
if( hs.Intersects( auxhs ) ){
return false;
}
}
}
return true;
}
/*
1.1 Function ~HoleEdgeContain~
*/
bool Region2::HoleEdgeContain(
const Reg2PreciseHalfSegment& hs ) const
{
assert( IsDefined() );
if( !IsEmpty() ) {
return false;
}
Reg2PreciseHalfSegment auxhs;
for( int i = 0; i < Size(); i++ ){
Get( i, auxhs );
if( auxhs.IsLeftDomPoint() &&
auxhs.attr.cycleno > 0 &&
hs.Inside( auxhs ) ){
return true;
}
}
return false;
}
/*
1.1 Assignment operator ~operator=~
*/
Region2& Region2::operator=( const Region2& r )
{
// cout << "Region2::operator=..." << endl;
assert( r.IsOrdered() );
ordered = true;
scaleFactor = r.scaleFactor;
gridCoordinates.copyFrom(r.gridCoordinates);
precCoordinates.copyFrom(r.precCoordinates);
preciseCoordinates.copyFrom(r.preciseCoordinates);
precHSvector = r.precHSvector;
bbox = r.bbox;
noComponents = r.noComponents;
maxIntx = r.maxIntx;
maxInty = r.maxInty;
minIntx = r.minIntx;
minInty = r.minInty;
maxPrecx = r.maxPrecx;
maxPrecy = r.maxPrecy;
minPrecx = r.minPrecx;
minPrecy = r.minPrecy;
return *this;
}
/*
1.1 Adding operator ~operator+=~
*/
Region2& Region2::operator+=( const Reg2PreciseHalfSegment& hs )
{
assert(IsDefined());
if( IsEmpty() )
bbox = hs.BoundingBox();
else
bbox = bbox.Union( hs.BoundingBox() );
if( !IsOrdered() )
{
precHSvector.push_back(hs);
}
else
{
if ( hs < precHSvector.front() )
precHSvector.insert(precHSvector.begin(), hs);
else if ( hs > precHSvector.back() )
precHSvector.push_back(hs);
else
{
for( vector<Reg2PreciseHalfSegment>::iterator
it=precHSvector.begin();
it!=precHSvector.end(); it++ )
if ( hs < *it)
{
precHSvector.insert(it, hs);
break;
}
}
}
if (cmp(hs.GetLeftPoint().x, maxPrecx) > 0) maxPrecx = hs.GetLeftPoint().x;
if (cmp(hs.GetLeftPoint().y, maxPrecy) > 0) maxPrecy = hs.GetLeftPoint().y;
if (cmp(hs.GetRightPoint().x, maxPrecx) > 0) maxPrecx = hs.GetRightPoint().x;
if (cmp(hs.GetRightPoint().y, maxPrecy) > 0) maxPrecy = hs.GetRightPoint().y;
if (cmp(hs.GetLeftPoint().x, minPrecx) < 0) minPrecx = hs.GetLeftPoint().x;
if (cmp(hs.GetLeftPoint().y, minPrecy) < 0) minPrecy = hs.GetLeftPoint().y;
if (cmp(hs.GetRightPoint().x, minPrecx) < 0) minPrecx = hs.GetRightPoint().x;
if (cmp(hs.GetRightPoint().y, minPrecy) < 0) minPrecy = hs.GetRightPoint().y;
return *this;
}
/*
1.1 Functions ~AddPreciseHalfsegment~
*/
Region2& Region2::AddPreciseHalfsegment( const bool ldp,
const Reg2PrecisePoint& pl,
const Reg2PrecisePoint& pr)
{
Reg2PreciseHalfSegment hs = Reg2PreciseHalfSegment(ldp, pl, pr);
return *this += hs;
}
Region2& Region2::AddPreciseHalfsegment( const bool ldp,
const int xl,
const mpq_class xlp,
const int yl,
const mpq_class ylp,
const int xr,
const mpq_class xrp,
const int yr,
const mpq_class yrp,
const int scale)
{
Reg2PrecisePoint pl = Reg2PrecisePoint(xlp, xl, ylp, yl);
Reg2PrecisePoint pr = Reg2PrecisePoint(xrp, xr, yrp, yr);
return AddPreciseHalfsegment(ldp, pl, pr);
}
/*
1.1 Function ~Intersects~
*/
bool Region2::Intersects( const Region2 &r ) const
{
assert( IsDefined() );
assert( r.IsDefined() );
if( IsEmpty() || r.IsEmpty() ){
return false;
}
if( !BoundingBox().Intersects( r.BoundingBox() ) ){
return false;
}
assert( IsOrdered() );
assert( r.IsOrdered() );
if( Inside( r ) || r.Inside( *this ) ){
return true;
}
Reg2PreciseHalfSegment hs1, hs2;
for( int i = 0; i < Size(); i++ ){
Get( i, hs1 );
if( hs1.IsLeftDomPoint() ){
for( int j = 0; j < r.Size(); j++ ){
r.Get( j, hs2 );
if( hs2.IsLeftDomPoint() &&
hs1.Intersects( hs2 ) ){
return true;
}
}
}
}
return false;
}
/*
1.1 Function ~Inside~
*/
bool Region2::Inside( const Region2& r ) const
{
assert( IsDefined() );
assert( r.IsDefined() );
if(!IsDefined() || !r.IsDefined() ){
return false;
}
if( IsEmpty() ){
return true;
}
if(r.IsEmpty()){
return false;
}
assert( IsOrdered() );
assert( r.IsOrdered() );
if( !r.BoundingBox().Contains( bbox ) ){
return false;
}
Reg2PreciseHalfSegment hs1, hs2;
for( int i = 0; i < Size(); i++ ){
Get( i, hs1 );
if( hs1.IsLeftDomPoint() ){
if( !r.Contains( hs1 ) ){
return false;
}
}
}
bool existhole = false,
allholeedgeinside = true;
for( int j = 0; j < r.Size(); j++ ){
r.Get( j, hs2 );
if( hs2.IsLeftDomPoint() &&
hs2.attr.cycleno > 0 ){
//hs2 is not masked by another face of Region2
if( !HoleEdgeContain( hs2 ) ){
existhole=true;
if( !Contains( hs2 ) ){
allholeedgeinside=false;
}
}
}
}
if( existhole && allholeedgeinside ){
return false;
}
return true;
}
/*
1.1 Function ~Adjacent~
*/
bool Region2::Adjacent( const Region2& r ) const
{
assert( IsDefined() );
assert( r.IsDefined() );
if( IsEmpty() || r.IsEmpty() ){
return false;
}
if( !BoundingBox().Intersects( r.BoundingBox() ) ){
return false;
}
assert( IsOrdered() );
assert( r.IsOrdered() );
if( Inside( r ) || r.Inside( *this ) )
return false;
Reg2PreciseHalfSegment hs1, hs2;
bool found = false;
for( int i = 0; i < Size(); i++ ){
Get( i, hs1 );
if( hs1.IsLeftDomPoint() ){
for( int j = 0; j < r.Size(); j++ ){
r.Get( j, hs2 );
if( hs2.IsLeftDomPoint() && hs1.Intersects( hs2 ) ){
if( hs1.Crosses( hs2 ) ){
return false;
}
found = true;
}
}
}
}
return found;
}
/*
1.1 Function ~Overlaps~
*/
bool Region2::Overlaps( const Region2& r ) const
{
assert( IsDefined() );
assert( r.IsDefined() );
if( IsEmpty() || r.IsEmpty() ){
return false;
}
if( !BoundingBox().Intersects( r.BoundingBox() ) ){
return false;
}
assert( IsOrdered() );
assert( r.IsOrdered() );
if( Inside( r ) || r.Inside( *this ) )
return true;
Reg2PreciseHalfSegment hs1, hs2;
for( int i = 0; i < Size(); i++ ){
Get( i, hs1 );
if( hs1.IsLeftDomPoint() ){
for( int j = 0; j < r.Size(); j++ ){
r.Get( j, hs2 );
if( hs2.IsLeftDomPoint() ){
if( hs2.Crosses( hs1 ) ){
return true;
}
}
}
}
}
return false;
}
/*
1.1 Function ~Area~
*/
double Region2::Area() const
{
assert( IsDefined() );
int n = Size();
double area = 0.0;
mpq_class precArea(0);
mpq_class a(0);
mpq_class x0(0);
mpq_class y0(0);
mpq_class x1(0);
mpq_class y1(0);
// get minimum with respect to Y-dimension
mpq_class minY (MIN(BoundingBox().MinD(1), +0.0));
Reg2PreciseHalfSegment hs;
for(int i=0; i < n; i++)
{
Get( i, hs );
if( hs.IsLeftDomPoint() ){ // use only one halfsegment
x0 = hs.GetLeftPoint().x;
x0.canonicalize();
x1 = hs.GetRightPoint().x;
x1.canonicalize();
// y0, y1 must be >= 0, so we correct them
y0 = hs.GetLeftPoint().y - minY;
y0.canonicalize();
y1 = hs.GetRightPoint().y - minY;
y1.canonicalize();
a = (x1-x0) * ((y1+y0) / 2);
a.canonicalize();
if ( hs.attr.insideAbove ){
a = -a;
}
precArea += a;
}
}
area = precArea.get_d();
return area;
}
/*
1.1 Function ~Translate~
*/
void Region2::Translate( const double& x,
const double& y, Region2& result ) const
{
result.Clear();
if( !IsDefined() ) {
result.SetDefined( false );
return;
}
result.SetDefined( true );
assert( IsOrdered() );
Reg2PreciseHalfSegment hs;
result.StartBulkLoad();
for( int i = 0; i < Size(); i++ )
{
Get( i, hs );
hs.Translate( x, y );
if ( overflowAsInt(hs.GetLeftPoint().x,
hs.GetRightPoint().x, scaleFactor) )
{
cerr << "Overflow of Int values: x-translation with value "
<< x << " is too big!" << endl;
result.SetDefined( false );
return;
}
if ( overflowAsInt(hs.GetLeftPoint().y,
hs.GetRightPoint().y, scaleFactor) )
{
cerr << "Overflow of Int values: y-translation with value "
<< y << " is too big!" << endl;
result.SetDefined( false );
return;
}
result += hs;
}
result.SetNoComponents( NoComponents() );
result.SetScaleFactor( scaleFactor );
result.EndBulkLoad( false, false, false, false, true );
}
/*
1.1 Function ~Compare~
*/
int Region2::Compare( const Attribute* arg ) const
{
Region2* cr = (Region2* )(arg);
if ( !cr )
return -2;
if (!IsDefined() && (!cr->IsDefined())){
return 0;
}
if(!IsDefined()){
return -1;
}
if(!cr->IsDefined()){
return 1;
}
if(Size()<cr->Size()){
return -1;
}
if(Size()>cr->Size()){
return 1;
}
if(Size()==0){ // two empty regions
return 0;
}
int bboxCmp = bbox.Compare( &cr->bbox );
if(bboxCmp!=0){
return bboxCmp;
}
Reg2PreciseHalfSegment hs1, hs2;
for( unsigned int i = 0; i < precHSvector.size(); i++ ) {
hs1 = precHSvector[i];
cr->Get( i, hs2 );
int hsCmp = hs1.Compare(hs2);
if(hsCmp!=0){
return hsCmp;
}
}
return 0;
}
/*
1.1 Function ~Print~
*/
ostream& Region2::Print( ostream &os ) const
{
os << "<";
if( !IsDefined() ) {
os << " undefined ";
} else {
Reg2PreciseHalfSegment hs;
for( unsigned int i = 0; i < precHSvector.size(); i++ )
{
hs = precHSvector[i];
os << " " << hs;
}
}
os << ">";
return os;
}
/*
1.1 Function ~Clone~
*/
Region2 *Region2::Clone() const
{
return new Region2( *this );
}
/*
1.1 Function ~HashValue~
*/
size_t Region2::HashValue() const
{
if(IsEmpty()) // subsumes !IsDefined()
return 0;
unsigned long h=0;
Reg2PreciseHalfSegment hs;
mpq_class x1, y1;
mpq_class x2, y2;
for( int i = 0; ((i < Size())&&(i<5)); i++ )
{
Get( i, hs );
x1=hs.GetLeftPoint().x;
y1=hs.GetLeftPoint().y;
x2=hs.GetRightPoint().x;
y2=hs.GetRightPoint().y;
h=h+(unsigned long)mpq_class((5*x1 + y1)+ (5*x2 + y2)).get_d();
}
return size_t(h);
}
/*
1.1 Function ~CopyFrom~
*/
void Region2::CopyFrom( const Attribute* right )
{
*this = *(const Region2 *)right;
}
/*
1.1 Function ~LogicSort~
*/
struct LogicSortReg2PreciseHalfSegment {
bool operator()( const Reg2PreciseHalfSegment& hs1,
const Reg2PreciseHalfSegment& hs2 ) {
return (hs1.LogicCompare(hs2) == -1);
}
};
void Region2::LogicSort()
{
if ( !IsDefined() ) {
return;
}
sort(precHSvector.begin(), precHSvector.end(),
LogicSortReg2PreciseHalfSegment() );
buildDbArrays();
ordered = true;
}
/*
1.1 Function ~Clear~
*/
void Region2::Clear()
{
gridCoordinates.clean();
precCoordinates.clean();
preciseCoordinates.clean();
precHSvector.clear();
ordered = true;
bbox.SetDefined(false);
}
/*
1.1 Function ~SetEmpty~
*/
void Region2::SetEmpty()
{
Clear();
SetDefined(true);
}
/*
1.1 Function ~SetPartnerNo~
*/
void Region2::SetPartnerNo()
{
if( !IsDefined() )
return;
int size = precHSvector.size();
int* tmp = new int[size/2];
memset(tmp,0,size*sizeof(int) / 2);
Reg2PreciseHalfSegment hs;
for( int i = 0; i < size; i++ )
{
Get( i, hs );
if( hs.IsLeftDomPoint() )
{
tmp[hs.attr.edgeno] = i;
}
else
{
int p = tmp[hs.attr.edgeno];
precHSvector[i].attr.partnerno = p;
precHSvector[p].attr.partnerno = i;
}
}
delete[] tmp;
}
/*
1.1 Function ~GetCycleDirection~
*/
bool Region2::GetCycleDirection() const
{
/*
Preconditions:
* The region must represent just one cycle!!!!
* It is need that the edgeno stores the order that the half segments were
typed, and the half segments must be sorted in the half segment order. In
other words if hs1.attr.edgeno is less than hs2.attr.edgeno then hs1 was
typed first than hs2.
This function has the purpose of choosing the A, P, and B points in order
to call the function that really computes the cycle direction.
As the point P is leftmost point then it is the left point of hs1 or
the left point of hs2 because in the half segment order these two points
are equal. Now the problem is to decide which of the right points are A
and B. At the first sight we could say that the point A is the right point
of the half segment with lowest partner number. However it is not true ever
because the APB connected points may be go over the
bound of the pointlist. This will be the case if the cycle is in the form
P,B,..,A and B,...,A,P. Nevertheless the segments are ordered in the half
segment order, and when the last half segment is been considered for choosing
the APB connected points, the point A will be always the right point of the
last segment.
*/
Reg2PrecisePoint pA, pP, pB;
Reg2PreciseHalfSegment hs1, hs2;
this->Get(0,hs1);
this->Get(1,hs2);
assert( hs1.GetLeftPoint()==hs2.GetLeftPoint() );
pP = hs1.GetLeftPoint();
// If we have the last half segment connected to the first half
// segment, the difference //between their partner numbers is
// more than one.
if (abs(hs1.attr.edgeno - hs2.attr.edgeno)>1)
{
if (hs1.attr.edgeno > hs2.attr.edgeno)
{
pA = hs1.GetRightPoint();
pB = hs2.GetRightPoint();
}
else
{
pA = hs2.GetRightPoint();
pB = hs1.GetRightPoint();
}
}
else
{
if (hs1.attr.edgeno < hs2.attr.edgeno)
{
pA = hs1.GetRightPoint();
pB = hs2.GetRightPoint();
}
else
{
pA = hs2.GetRightPoint();
pB = hs1.GetRightPoint();
}
}
if ( cmp(pA.x, pP.x) == 0 ) {//A --> P is a vertical segment
if ( cmp(pA.y, pP.y) > 0 ) {//A --> P directed downwards (case 1)
return false; //Counterclockwise
} else {//upwards (case 2)
return true; // Clockwise
}
}
if ( cmp(pB.x, pP.x) == 0 ) {//P --> B is a vertical segment
if ( cmp(pP.y, pB.y) > 0 ){ //downwords (case 3)
return false; //Conterclockwise
} else {//upwards (case 4)
return true; //Clockwise
}
}
//compute the slopes of P-->A and P-->B
mpq_class m_p_a = ( pA.y - pP.y ) / ( pA.x - pP.x );
m_p_a.canonicalize();
mpq_class m_p_b = ( pB.y - pP.y ) / ( pB.x - pP.x );
m_p_b.canonicalize();
if ( cmp(m_p_a, m_p_b) > 0 ) //case 5
return false;//counterclockwise
else //case 6
return true; //clockwise
}
//cycleDirection: true (cycle is clockwise) / false
// (cycle is counterclockwise)
//It is need that the attribute insideAbove of the
//half segments represents the order that their points
//were typed: true (left point, right point) /
//false (right point, left point).
/*
1.1 Function ~IsCriticalPoint~
*/
bool Region2::IsCriticalPoint( const Reg2PrecisePoint &adjacentPoint,
const int hsPosition ) const
{
int adjPosition = hsPosition,
adjacencyNo = 0,
step = 1;
do
{
Reg2PreciseHalfSegment adjCHS;
adjPosition+=step;
if ( adjPosition<0 || adjPosition>=this->Size())
break;
adjCHS = precHSvector[adjPosition];
if (!adjCHS.IsLeftDomPoint())
continue;
AttrType attr = adjCHS.GetAttr();
//When looking for critical points, the partner of
//the adjacent half segment found
//cannot be consired.
if (attr.partnerno == hsPosition)
continue;
if ( ( adjacentPoint==adjCHS.GetLeftPoint() ) ||
( adjacentPoint==adjCHS.GetRightPoint() ) )
adjacencyNo++;
else
{
if (step==-1)
return false;
step=-1;
adjPosition=hsPosition;
}
}
while (adjacencyNo<2);
return (adjacencyNo>1);
}
/*
1.1 Function ~GetAdjacentHS~
*/
bool Region2::GetAdjacentHS( const Reg2PreciseHalfSegment &hs,
const int hsPosition,
int &position,
const int partnerno,
const int partnernoP,
Reg2PreciseHalfSegment& adjacentCHS,
const Reg2PrecisePoint &adjacentPoint,
Reg2PrecisePoint &newAdjacentPoint,
bool *cycle,
int step) const
{
bool adjacencyFound=false;
do
{
position+=step;
if ( position<0 || position>=(int)precHSvector.size())
break;
adjacentCHS = precHSvector[position];
if (partnernoP == position)
continue;
if ( adjacentPoint==adjacentCHS.GetLeftPoint() ){
if (!cycle[position]){
newAdjacentPoint = adjacentCHS.GetRightPoint();
adjacencyFound = true;
}
}
else if ( adjacentPoint==adjacentCHS.GetRightPoint() ){
if (!cycle[position]){
newAdjacentPoint = adjacentCHS.GetLeftPoint();
adjacencyFound = true;
}
}
else
break;
}
while (!adjacencyFound);
return adjacencyFound;
}
/*
1.1 Function ~ComputeCycle~
*/
void Region2::ComputeCycle( Reg2PreciseHalfSegment &hs,
int faceno,
int cycleno,
int &edgeno,
bool *cycle )
{
Reg2PrecisePoint nextPoint = hs.GetLeftPoint(),
lastPoint = hs.GetRightPoint(),
previousPoint, *currentCriticalPoint=NULL;
AttrType attr, attrP;
Reg2PreciseHalfSegment hsP;
vector<SCycle2> sCycleVector;
SCycle2 *s=NULL;
do
{
if (s==NULL)
{
//Update attributes
attr = hs.GetAttr();
attr.faceno=faceno;
attr.cycleno=cycleno;
attr.edgeno=edgeno;
hs.SetAttr(attr);
hsP = precHSvector[attr.partnerno];
attrP = hsP.GetAttr();
attrP.faceno=faceno;
attrP.cycleno=cycleno;
attrP.edgeno=edgeno;
hsP.SetAttr(attrP);
precHSvector[attrP.partnerno].SetAttr(attr);
precHSvector[attr.partnerno].SetAttr(attrP);
edgeno++;
cycle[attr.partnerno]=true;
cycle[attrP.partnerno]=true;
if (this->IsCriticalPoint(nextPoint,attrP.partnerno))
currentCriticalPoint = new Reg2PrecisePoint(nextPoint);
s = new SCycle2(hs,attr.partnerno,hsP,attrP.partnerno,
currentCriticalPoint,nextPoint);
}
Reg2PreciseHalfSegment adjacentCHS;
Reg2PrecisePoint adjacentPoint;
bool adjacentPointFound=false;
previousPoint = nextPoint;
if (s->goToCHS1Right)
{
s->goToCHS1Right=GetAdjacentHS(s->hs1,
s->hs2Partnerno,
s->hs1PosRight,
s->hs1Partnerno,
s->hs2Partnerno,adjacentCHS,
previousPoint,
nextPoint,
cycle,
1);
adjacentPointFound=s->goToCHS1Right;
}
if ( !adjacentPointFound && s->goToCHS1Left )
{
s->goToCHS1Left=GetAdjacentHS(s->hs1,
s->hs2Partnerno,
s->hs1PosLeft,
s->hs1Partnerno,
s->hs2Partnerno,
adjacentCHS,
previousPoint,
nextPoint,
cycle,
-1);
adjacentPointFound=s->goToCHS1Left;
}
if (!adjacentPointFound && s->goToCHS2Right)
{
s->goToCHS2Right=GetAdjacentHS(s->hs2,
s->hs1Partnerno,
s->hs2PosRight,
s->hs2Partnerno,
s->hs1Partnerno,
adjacentCHS,
previousPoint,
nextPoint,
cycle,
1);
adjacentPointFound=s->goToCHS2Right;
}
if (!adjacentPointFound && s->goToCHS2Left)
{
s->goToCHS2Left=GetAdjacentHS(s->hs2,
s->hs1Partnerno,
s->hs2PosLeft,
s->hs2Partnerno,
s->hs1Partnerno,
adjacentCHS,
previousPoint,
nextPoint,
cycle,
-1);
adjacentPointFound = s->goToCHS2Left;
}
if(!adjacentPointFound){
cerr<<"previousPoint "<<previousPoint<<endl;
cerr << "Problem in rebuilding cycle in a region " << endl;
cerr << "no adjacent point found" << endl;
cerr << "Halfsegments : --------------- " << endl;
for( unsigned int i = 0; i < precHSvector.size(); i++){
cerr << i << " : " << (precHSvector[i]) << endl;
}
assert(adjacentPointFound); // assert(false)
}
sCycleVector.push_back(*s);
if ( (currentCriticalPoint!=NULL)
&& (*currentCriticalPoint==nextPoint) )
{
//The critical point defines a cycle, so it is need to
//remove the segments
//from the vector, and set the segment as not visited
//in the cycle array.
//FirsAux is the first half segment with the critical
//point equals to criticalPoint.
SCycle2 sAux,firstSCycle;
do
{
sAux=sCycleVector.back();
sCycleVector.pop_back();
firstSCycle=sCycleVector.back();
if (firstSCycle.criticalPoint==NULL)
break;
if (*firstSCycle.criticalPoint!=*currentCriticalPoint)
break;
cycle[sAux.hs1Partnerno]=false;
cycle[sAux.hs2Partnerno]=false;
edgeno--;
}while(sCycleVector.size()>1);
delete s;
//when s is deleted, the critical point is also deleted.
s = 0;
if (sCycleVector.size()==1)
{
sCycleVector.pop_back();
if(s){
delete s;
}
s = new SCycle2(firstSCycle);
}
else{
if(s){
delete s;
}
s= new SCycle2(sAux);
}
hs = s->hs1;
currentCriticalPoint=s->criticalPoint;
nextPoint=s->nextPoint;
continue;
}
if ( nextPoint==lastPoint )
{
//Update attributes
attr = adjacentCHS.GetAttr();
attr.faceno=faceno;
attr.cycleno=cycleno;
attr.edgeno=edgeno;
hs.SetAttr(attr);
hsP = precHSvector[attr.partnerno];
attrP = hsP.GetAttr();
attrP.faceno=faceno;
attrP.cycleno=cycleno;
attrP.edgeno=edgeno;
hsP.SetAttr(attrP);
precHSvector[attrP.partnerno].SetAttr(attr);
precHSvector[attr.partnerno].SetAttr(attrP);
edgeno++;
cycle[attr.partnerno]=true;
cycle[attrP.partnerno]=true;
break;
}
hs = adjacentCHS;
delete s;
s=NULL;
}
while(1);
if(s){
delete s;
s = 0;
}
}
/*
1.1 Function ~GetNewFaceNo~
*/
int Region2::GetNewFaceNo(const Reg2PreciseHalfSegment& hsIn,
const int startpos) const {
// Precondition:
// hsIn is the smallest (in halfsegment-order)
// segment of a cycle.
// startpos is the index of hsIn in the DBArray.
if (hsIn.GetAttr().insideAbove)
{
// hsIn belongs to a new face:
return -1;
}
// Now we know hsIn belongs to a new hole and we
// have to encounter the enclosing face.
// This is done by searching the next halfsegment
// maxHS 'under' hsIn.
// Since we go downwards, the facenumber of maxHS
// must be already known
// and is equal to the facenumber of hsIn.
mpq_class y0;
mpq_class maxY0;
Reg2PreciseHalfSegment hs;
Reg2PreciseHalfSegment maxHS;
bool hasMax = false;
const Reg2PrecisePoint& p = hsIn.GetLeftPoint();
const int coverno = hsIn.GetAttr().coverageno;
int touchedNo = 0;
int i = startpos -1;
bool first = true;
while (i >= 0 && touchedNo < coverno)
{
hs = precHSvector[i];
if (!hs.IsLeftDomPoint())
{
i--;
continue;
}
if ( cmp(hs.GetLeftPoint().x, p.x) <= 0 &&
cmp(p.x, hs.GetRightPoint().x) <= 0 )
{
touchedNo++;
}
if ( cmp(hs.GetRightPoint().x, p.x) != 0 &&
hs.RayDown(p, y0)) {
if (first ||
cmp(y0, maxY0) > 0 ||
( cmp(y0, maxY0) == 0 && hs > maxHS)) {
// To find the first halfsegment
// 'under' hsIn
// we compare them as follows:
// (1) y-value of the intersection
// point between a ray down from
// the left point of hsIn and hs.
// (2) halfsegment order.
maxY0 = y0;
maxHS = hs;
first = false;
hasMax = true;
}
}
i--;
}
if (!hasMax) {
cerr << "Problem in rebuilding cycle in a region " << endl;
cerr << "No outer cycle found" << endl;
cerr << "hsIn: " << hsIn << endl;
cerr << "Halfsegments : --------------- " << endl;
Reg2PreciseHalfSegment hs;
for ( unsigned int i = 0; i < precHSvector.size(); i++)
{
cerr << i << " : " << (precHSvector[i]) << endl;
}
assert(false);
}
//the new cycle is a holecycle of the face ~maxHS.attr.faceno~
return maxHS.GetAttr().faceno;
}
/*
1.1 Function ~ComputeRegion~
*/
void Region2::ComputeRegion()
{
if( !IsDefined() )
return;
//array that stores in position i the
//last cycle number of the face i
vector<int> face;
//array that stores in the position ~i~
//if the half segment hi had
//already the face number, the cycle
//number and the edge number
//attributes set properly, in other
//words, it means that hi is already
//part of a cycle
bool *cycle;
int lastfaceno=0,
faceno=0,
cycleno = 0,
edgeno = 0;
bool isFirstCHS=true;
int size = precHSvector.size();
if (size==0)
return;
//Insert in the vector the first cycle of the first face
face.push_back(0);
cycle = new bool[size];
#ifdef SECONDO_MAC_OSX
// something goes wrong at mac osx and the memset function
for(int i=0;i<size;i++){
cycle[i] = false;
}
#else
memset( cycle, 0, size*sizeof(bool) );
#endif
for (int i=0; i<size; i++)
{
Reg2PreciseHalfSegment aux(precHSvector[i]);
if ( aux.IsLeftDomPoint() && !cycle[i])
{
if(!isFirstCHS)
{
int facenoAux = GetNewFaceNo(aux,i);
if (facenoAux==-1)
{
//The lhs half segment will start a new face
lastfaceno++;
faceno = lastfaceno;
//to store the first cycle number of the face lastFace
face.push_back(0);
cycleno = 0;
edgeno = 0;
}
else
{
//The half segment ~hs~ belongs to an existing face
faceno = facenoAux;
face[faceno]++;
cycleno = face[faceno];
edgeno = 0;
}
}
else
{
isFirstCHS = false;
}
ComputeCycle(aux, faceno,cycleno, edgeno, cycle);
}
}
delete [] cycle;
noComponents = lastfaceno + 1;
}
/*
1.1 Function ~buildDbArrays~
*/
void Region2::buildDbArrays()
{
if (precHSvector.size() < 1) return;
gridCoordinates.clean();
precCoordinates.clean();
preciseCoordinates.clean();
maxIntx = 0;
maxInty = 0;
minIntx = 0;
minInty = 0;
Reg2PreciseHalfSegment hs;
Reg2GridHalfSegment gHS;
Reg2PrecHalfSegment pHS;
for (unsigned int i=0; i < precHSvector.size(); i++)
{
hs = precHSvector[i];
Reg2PrecisePoint lp = hs.GetLeftPoint();
Reg2PrecisePoint rp = hs.GetRightPoint();
mpz_t sFactor;
mpz_init(sFactor);
mpq_class sFac(0);
uint sfactor;
if (scaleFactor < 0)
{
sfactor = -scaleFactor;
mpz_ui_pow_ui(sFactor, 10, sfactor);
sFac = mpq_class(mpz_class(1), mpz_class(sFactor));
}
else
{
sfactor = scaleFactor;
mpz_ui_pow_ui(sFactor, 10, sfactor);
sFac = mpq_class(mpz_class(sFactor), mpz_class(1));
}
sFac.canonicalize();
mpz_clear(sFactor);
mpq_class lxs = lp.x * sFac;
lxs.canonicalize();
mpq_class lys = lp.y * sFac;
lys.canonicalize();
mpq_class rxs = rp.x * sFac;
rxs.canonicalize();
mpq_class rys = rp.y * sFac;
rys.canonicalize();
int lxi = (int)floor(lxs.get_d());
if (lxi > maxIntx) maxIntx = lxi;
if (lxi < minIntx) minIntx = lxi;
int lyi = (int)floor(lys.get_d());
if (lyi > maxInty) maxInty = lyi;
if (lyi < minInty) minInty = lyi;
Reg2GridPoint lgp(lxi, lyi);
int rxi = (int)floor(rxs.get_d());
if (rxi > maxIntx) maxIntx = rxi;
if (rxi < minIntx) minIntx = rxi;
int ryi = (int)floor(rys.get_d());
if (ryi > maxInty) maxInty = ryi;
if (ryi < minInty) minInty = ryi;
Reg2GridPoint rgp(rxi, ryi);
mpq_class lxr = lxs - lxi;
lxr.canonicalize();
mpq_class lyr = lys - lyi;
lyr.canonicalize();
mpq_class rxr = rxs - rxi;
rxr.canonicalize();
mpq_class ryr = rys - ryi;
ryr.canonicalize();
gHS = Reg2GridHalfSegment(hs.IsLeftDomPoint(), lxi, lyi,
rxi, ryi);
gHS.SetAttr(hs.attr);
gridCoordinates.Append(gHS);
pHS = Reg2PrecHalfSegment(-1);
pHS.SetlPointx(lxr, &preciseCoordinates);
pHS.SetlPointy(lyr, &preciseCoordinates);
pHS.SetrPointx(rxr, &preciseCoordinates);
pHS.SetrPointy(ryr, &preciseCoordinates);
precCoordinates.Append(pHS);
gridCoordinates.Get(i, gHS);
precCoordinates.Get(i, pHS);
gridCoordinates.TrimToSize();
precCoordinates.TrimToSize();
preciseCoordinates.TrimToSize();
}
}
/*
1.1 Function ~buildHSvector~
*/
void Region2::buildHSvector()
{
Reg2PreciseHalfSegment hs;
Reg2GridHalfSegment gHS;
Reg2PrecHalfSegment pHS;
precHSvector.clear();
maxPrecx = mpq_class(0);
maxPrecy = mpq_class(0);
minPrecx = mpq_class(0);
minPrecy = mpq_class(0);
for (int i=0; i < gridCoordinates.Size(); i++)
{
gridCoordinates.Get(i, gHS);
precCoordinates.Get(i, pHS);
mpz_t sFactor;
mpz_init(sFactor);
mpq_class sFac(0);
uint sfactor;
if (scaleFactor < 0)
{
sfactor = -scaleFactor;
mpz_ui_pow_ui(sFactor, 10, sfactor);
sFac = mpq_class(mpz_class(sFactor), mpz_class(1));
}
else
{
sfactor = scaleFactor;
mpz_ui_pow_ui(sFactor, 10, sfactor);
sFac = mpq_class(mpz_class(1), mpz_class(sFactor));
}
sFac.canonicalize();
mpz_clear(sFactor);
mpq_class lx = (pHS.GetlPointx(&preciseCoordinates)
+ gHS.GetLeftPointX()) * sFac;
lx.canonicalize();
mpq_class ly = (pHS.GetlPointy(&preciseCoordinates)
+ gHS.GetLeftPointY()) * sFac;
ly.canonicalize();
mpq_class rx = (pHS.GetrPointx(&preciseCoordinates)
+ gHS.GetRightPointX()) * sFac;
rx.canonicalize();
mpq_class ry = (pHS.GetrPointy(&preciseCoordinates)
+ gHS.GetRightPointY()) * sFac;
ry.canonicalize();
if (cmp(lx, maxPrecx) > 0) maxPrecx = lx;
if (cmp(ly, maxPrecy) > 0) maxPrecy = ly;
if (cmp(rx, maxPrecx) > 0) maxPrecx = rx;
if (cmp(ry, maxPrecy) > 0) maxPrecy = ry;
if (cmp(lx, minPrecx) < 0) minPrecx = lx;
if (cmp(ly, minPrecy) < 0) minPrecy = ly;
if (cmp(rx, minPrecx) < 0) minPrecx = rx;
if (cmp(ry, minPrecy) < 0) minPrecy = ry;
Reg2PrecisePoint pl = Reg2PrecisePoint(lx, ly);
Reg2PrecisePoint pr = Reg2PrecisePoint(rx, ry);
hs = Reg2PreciseHalfSegment(gHS.IsLeftDomPoint(), pl, pr);
AttrType attr = AttrType(gHS.GetAttr());
hs.SetAttr(attr);
precHSvector.push_back(hs);
}
}
/*
1.1 Function ~validateRegion2~
*/
bool Region2::validateRegion2()
{
// return true;
Reg2PreciseHalfSegment hsi, hsj;
Reg2PrecisePoint pp;
for( unsigned int i = 0; i < precHSvector.size()-1; i++ )
{
Get( i, hsi );
hsj = hsi;
if (hsi.IsLeftDomPoint())
{
for( unsigned int j = i+1; j < precHSvector.size()
&& hsj.GetLeftPoint() < hsi.GetRightPoint();
j++ )
{
Get( j, hsj );
if (hsj.IsLeftDomPoint())
{
if (hsi.Intersects(hsj))
{
if ((hsi.attr.faceno!=hsj.attr.faceno) ||
(hsi.attr.cycleno!=hsj.attr.cycleno))
{
if ( !hsi.Intersection(hsj, pp) ||
( pp != hsi.GetLeftPoint() && pp != hsi.GetRightPoint() &&
pp != hsj.GetLeftPoint() && pp != hsj.GetRightPoint() ))
{
cout << "two cycles intersect with the ";
cout << "following edges:";
cout << hsj << " :: " << hsi << endl;
return false;
}
}
else
{
if ((hsj.GetLeftPoint()==hsi.GetLeftPoint()) &&
(hsj.GetRightPoint()==hsi.GetRightPoint()))
{
cout << "two edges: " << hsj << " :: " << hsi
<< " are the same!"
<< endl;
return false;
}
if ((hsj.GetLeftPoint()!=hsi.GetLeftPoint()) &&
(hsj.GetLeftPoint()!=hsi.GetRightPoint()) &&
(hsj.GetRightPoint()!=hsi.GetLeftPoint()) &&
(hsj.GetRightPoint()!=hsi.GetRightPoint()))
{
cout << "two edges: " << hsj << " :: " << hsi
<< " of the same cycle intersect in middle!"
<< endl;
return false;
}
}
}
}
}
}
}
vector<Region2*> comps;
Components(comps);
Region2 reg2(0);
vector<Region2*> regparts;
vector<vector<Region2*> > faces;
vector<vector<Region2*> > faceholes;
for (unsigned int i = 0; i < comps.size(); i++)
{
comps[i]->getFaces(reg2);
reg2.Components(regparts);
faces.push_back(regparts);
comps[i]->getHoles(reg2);
reg2.Components(regparts);
faceholes.push_back(regparts);
}
for (unsigned int i = 0; i < comps.size()-1; i++)
{
for (unsigned int j = i+1; j < comps.size(); j++)
{
if ( faces[j][0]->Inside(*faces[i][0]) )
{
bool insidefound = false;
for (unsigned int k = 0; k < faceholes[i].size()
&& !insidefound; k++)
{
if ( faces[j][0]->Inside(*faceholes[i][k]) )
insidefound = true;
}
if ( !insidefound )
{
cout << "one face is inside another face!" << endl;
return false;
}
}
if ( faces[i][0]->Inside(*faces[j][0]) )
{
bool insidefound = false;
for (unsigned int k = 0; k < faceholes[j].size()
&& !insidefound; k++)
{
if ( faces[i][0]->Inside(*faceholes[j][k]) )
insidefound = true;
}
if ( !insidefound )
{
cout << "one face is inside another face!" << endl;
return false;
}
}
}
for (unsigned int j = 0; j < faceholes[i].size(); j++)
{
if ( !faceholes[i][j]->Inside(*faces[i][0]) )
{
cout << "one hole is not inside the face!" << endl;
return false;
}
for (unsigned int k = j+1;
k < faceholes[j].size(); k++)
if ( faceholes[i][j]->Inside(*faceholes[i][k])
|| faceholes[i][k]->Inside(*faceholes[i][j]) )
{
cout << "one hole is inside another hole!" << endl;
return false;
}
}
}
return true;
}
/*
1.1 Function ~Components~
*/
void Region2::Components( vector<Region2*>& components )
{
vector<int> edgeno;
components.clear();
if ( IsEmpty() ) // subsumes IsDefined()
{
return;
}
for (int i=0; i < noComponents; i++)
{
components.push_back(new Region2(1));
components[i]->StartBulkLoad();
edgeno.push_back(0);
}
Reg2PreciseHalfSegment hs;
for (int i=0; i < Size(); i++)
{
Get(i,hs);
if ( hs.IsLeftDomPoint() )
{
int face = hs.attr.faceno;
hs.attr.faceno = 0;
hs.attr.edgeno = edgeno[face]++;
(*components[face]) += hs;
hs.SetLeftDomPoint(!hs.IsLeftDomPoint());
(*components[face]) += hs;
}
}
for (int i=0; i < noComponents; i++)
{
components[i]->SetNoComponents( 1 );
components[i]->SetScaleFactor(scaleFactor, false);
components[i]->EndBulkLoad();
}
}
/*
1.1 Function ~getFaces~
*/
void Region2::getFaces(Region2& result) const
{
if (!IsDefined())
{
result.SetDefined(false);
}
result.Clear();
result.SetDefined(true);
result.StartBulkLoad();
int edgeno = 0;
for (int i=0; i < Size(); i++)
{
Reg2PreciseHalfSegment hs;
Get(i,hs);
if (hs.IsLeftDomPoint())
{
if (hs.attr.cycleno==0) // only the outer cycles
{
hs.attr.edgeno = edgeno;
result += hs;
hs.SetLeftDomPoint(!hs.IsLeftDomPoint());
result += hs;
edgeno++;
}
}
}
result.SetScaleFactor(scaleFactor, false);
result.EndBulkLoad();
}
/*
1.1 Function ~getHoles~
*/
void Region2::getHoles(Region2& result) const
{
if (!IsDefined())
{
result.SetDefined(false);
}
result.Clear();
result.SetDefined(true);
result.StartBulkLoad();
int edgeno = 0;
for (int i=0; i < Size(); i++)
{
Reg2PreciseHalfSegment hs;
Get(i,hs);
if (hs.IsLeftDomPoint())
{
if (hs.attr.cycleno!=0) // not the outer cycle
{
hs.attr.edgeno = edgeno;
hs.attr.insideAbove = ! hs.attr.insideAbove;
result += hs;
hs.SetLeftDomPoint(!hs.IsLeftDomPoint());
result += hs;
edgeno++;
}
}
}
result.SetScaleFactor(scaleFactor, false);
result.EndBulkLoad();
}
/*
1.1 Function ~SetOutType~
*/
int Region2::outType = 0;
bool Region2::SetOutType(int i) {
if ( i == 0 || i == 1 ) {
outType = i;
return true;
}
return false;
}
/*
1 Definition of the Region2Algebra
1.1 ~Region2Property~
*/
ListExpr Region2Property()
{
ListExpr listreplist = nl->TextAtom();
nl->AppendText(listreplist,
"Version 1: is the standard representation with\n"
"(<int> (<face>*)), where <int> represents the "
"scaleFactor,\n<face> is (<outercycle>"
"<holecycle>*), <outercycle> and\n<holecycle> are"
" (<precisePoint>*). Each <precisePoint> "
"consists of (<int> <int> <precisePart>), with "
"<precisePart> as (<text> <text>) or empty list, "
"representing X and Y values "
"separated in an integer part and a text with a "
"rational number representing the precise "
"remainder (value between 0 and 1). Each precise "
"coordinate is calculated by\n"
"( integer-value + precisePart ) * "
"10 ^(-scaleFactor)\n"
"Version 2: (<face>*), where <face> is\n(<outercycle>"
"<holecycle>*), <outercycle> and <holecycle> are"
" (<precisePoint>*).\nEach <precisePoint> consists"
" of (<text> <text>) representing X and Y as real"
" values with arbitrary precision.\n"
"The predefined scaleFactor is 0.\n"
"If the values of X and Y are too big resulting in an "
"integer overflow, an error is reported.\n"
"Version 3: (<face>*), where <face> is\n(<outercycle>"
"<holecycle>*), <outercycle> and <holecycle> are "
"<points>*.\nThis is the same definition like the "
"region data type, with a predefined scaleFactor of 0.\n"
"If the point-values are too big resulting in an "
"integer overflow, an error is reported.");
ListExpr examplelist = nl->TextAtom();
nl->AppendText(examplelist,
"Version 1: (2 ((((3 0 ())(10 1 ())(3 1 ()))((3 0 ('1/10' "
"'1/10'))(3 0 ('1/10' '9/10'))(6 0 ('0' '8/10'))))))\n"
"Version 2: (((('1.298262036' '1.888212877')('1.11177987207'"
" '10.112877')('5.29826225622263094' "
"'10.22666432466989809822'))))\n"
"Version 3: (((3 0)(10 1)(3 1))((3.1 0.1)(3.1 0.9)"
"(6 0.8)))");
ListExpr remarkslist = nl->TextAtom();
nl->AppendText(remarkslist,
"all <holecycle> must be completely "
"within <outercycle>.");
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("-> DATA"),
nl->StringAtom(Region2::BasicType()),
listreplist,
examplelist,
remarkslist)));
}
/*
1.1 ~OutPoint~
*/
ListExpr OutPoint( Region2* r, int i, bool left )
{
ListExpr precX, precY;
Reg2GridHalfSegment gHS;
Reg2PrecHalfSegment pHS;
r->getgridCoordinates()->Get(i, gHS);
r->getprecCoordinates()->Get(i, pHS);
if ( left )
{
mpq_class x = pHS.GetlPointx(r->getpreciseCoordinates());
mpq_class y = pHS.GetlPointy(r->getpreciseCoordinates());
if ( cmp(x, 0) != 0 || cmp(y, 0) != 0 )
{
gmpTypeToTextType1( x, precX );
gmpTypeToTextType1( y, precY );
return nl->ThreeElemList( nl->IntAtom( gHS.GetLeftPointX() ),
nl->IntAtom( gHS.GetLeftPointY() ),
nl->TwoElemList( precX, precY ) );
}
else
return nl->ThreeElemList( nl->IntAtom( gHS.GetLeftPointX() ),
nl->IntAtom( gHS.GetLeftPointY() ),
nl->TheEmptyList() );
}
else
{
mpq_class x = pHS.GetrPointx(r->getpreciseCoordinates());
mpq_class y = pHS.GetrPointy(r->getpreciseCoordinates());
if ( cmp(x, 0) != 0 || cmp(y, 0) != 0 )
{
gmpTypeToTextType1( x, precX );
gmpTypeToTextType1( y, precY );
return nl->ThreeElemList( nl->IntAtom( gHS.GetRightPointX() ),
nl->IntAtom( gHS.GetRightPointY() ),
nl->TwoElemList( precX, precY ) );
}
else
return nl->ThreeElemList( nl->IntAtom( gHS.GetRightPointX() ),
nl->IntAtom( gHS.GetRightPointY() ),
nl->TheEmptyList() );
}
}
/*
1.1 ~OutPoint2~
*/
ListExpr OutPoint2( Region2* r, int i, bool left )
{
ListExpr precX, precY;
Reg2PreciseHalfSegment pHS;
Reg2PrecisePoint pP;
r->Get(i, pHS);
if ( left )
{
pP = pHS.GetLeftPoint();
}
else
{
pP = pHS.GetRightPoint();
}
gmpTypeToTextType2( pP.x, precX );
gmpTypeToTextType2( pP.y, precY );
return nl->TwoElemList( precX, precY );
}
/*
1.1 ~OutRegion2~
*/
ListExpr OutRegion2( ListExpr typeInfo, Word value )
{
Region2* r = (Region2*)(value.addr);
if ( !r->IsDefined() )
{
return nl->SymbolAtom(Symbol::UNDEFINED());
}
if (r->precHSvectorIsEmpty()) r->buildHSvector();
if( r->IsEmpty() )
{
return (nl->TheEmptyList());
}
else
{
Region2 *RCopy=new Region2(*r, true); // in memory
RCopy->LogicSort();
Reg2PreciseHalfSegment hs, hsnext;
ListExpr regionNL = nl->TheEmptyList();
ListExpr regionNLLast = regionNL;
ListExpr faceNL = nl->TheEmptyList();
ListExpr faceNLLast = faceNL;
ListExpr cycleNL = nl->TheEmptyList();
ListExpr cycleNLLast = cycleNL;
ListExpr pointNL = nl->TheEmptyList();
// avoid uninitialized use
int currFace = -999999, currCycle= -999999;
Reg2PrecisePoint outputP, leftoverP;
bool left;
for ( int i = 0; i < RCopy->Size(); i++ )
{
RCopy->Get( i, hs);
if (i==0)
{
currFace = hs.attr.faceno;
currCycle = hs.attr.cycleno;
RCopy->Get( i+1, hsnext);
if ((hs.GetLeftPoint() == hsnext.GetLeftPoint()) ||
((hs.GetLeftPoint() == hsnext.GetRightPoint())))
{
outputP = hs.GetRightPoint();
left = false;
leftoverP = hs.GetLeftPoint();
}
else
if ((hs.GetRightPoint() == hsnext.GetLeftPoint()) ||
((hs.GetRightPoint() == hsnext.GetRightPoint())) )
{
outputP = hs.GetLeftPoint();
left = true;
leftoverP = hs.GetRightPoint();
}
else
{
cerr << "\n" << __PRETTY_FUNCTION__
<< ": Wrong data format --- "
<< "discontiguous segments!" << endl
<< "\ths = " << hs << endl
<< "\thsnext = " << hsnext << endl;
return nl->SymbolAtom(Symbol::UNDEFINED());
}
if (Region2::outType == 0)
pointNL = OutPoint( RCopy, i, left );
if (Region2::outType == 1)
pointNL = OutPoint2( RCopy, i, left );
if (cycleNL == nl->TheEmptyList())
{
cycleNL = nl->OneElemList(pointNL);
cycleNLLast = cycleNL;
}
else
{
cycleNLLast = nl->Append( cycleNLLast, pointNL );
}
}
else
{
if (hs.attr.faceno == currFace)
{
if (hs.attr.cycleno == currCycle)
{
outputP=leftoverP;
if (hs.GetLeftPoint() == leftoverP)
{
left = true;
leftoverP = hs.GetRightPoint();
}
else if (hs.GetRightPoint() == leftoverP)
{
left = false;
leftoverP = hs.GetLeftPoint();
}
else
{
cerr << "\n" << __PRETTY_FUNCTION__
<< ": Wrong data format --- "
<< "discontiguous segment in cycle!" << endl
<< "\thh = " << hs << endl
<< "\tleftoverP = " << leftoverP << endl;
return nl->SymbolAtom(Symbol::UNDEFINED());
}
if (Region2::outType == 0)
pointNL=OutPoint( RCopy, i, left );
if (Region2::outType == 1)
pointNL=OutPoint2( RCopy, i, left );
if (cycleNL == nl->TheEmptyList())
{
cycleNL=nl->OneElemList(pointNL);
cycleNLLast = cycleNL;
}
else
{
cycleNLLast = nl->Append(cycleNLLast, pointNL);
}
}
else
{
if (faceNL == nl->TheEmptyList())
{
faceNL = nl->OneElemList(cycleNL);
faceNLLast = faceNL;
}
else
{
faceNLLast = nl->Append(faceNLLast, cycleNL);
}
cycleNL = nl->TheEmptyList();
currCycle = hs.attr.cycleno;
RCopy->Get( i+1, hsnext);
if ((hs.GetLeftPoint() == hsnext.GetLeftPoint()) ||
((hs.GetLeftPoint() == hsnext.GetRightPoint())))
{
outputP = hs.GetRightPoint();
left = false;
leftoverP = hs.GetLeftPoint();
}
else
if ((hs.GetRightPoint() == hsnext.GetLeftPoint()) ||
((hs.GetRightPoint() == hsnext.GetRightPoint())))
{
outputP = hs.GetLeftPoint();
left = true;
leftoverP = hs.GetRightPoint();
}
else
{
cerr << "\n" << __PRETTY_FUNCTION__
<< ": Wrong data format --- "
<< "discontiguous segments in cycle!" << endl
<< "\ths = " << hs << endl
<< "\thsnext = " << hsnext << endl;
return nl->SymbolAtom(Symbol::UNDEFINED());
}
if (Region2::outType == 0)
pointNL = OutPoint( RCopy, i, left );
if (Region2::outType == 1)
pointNL = OutPoint2( RCopy, i, left );
if (cycleNL == nl->TheEmptyList())
{
cycleNL = nl->OneElemList(pointNL);
cycleNLLast = cycleNL;
}
else
{
cycleNLLast = nl->Append(cycleNLLast, pointNL);
}
}
}
else
{
if (faceNL == nl->TheEmptyList())
{
faceNL = nl->OneElemList(cycleNL);
faceNLLast = faceNL;
}
else
{
faceNLLast = nl->Append(faceNLLast, cycleNL);
}
cycleNL = nl->TheEmptyList();
if (regionNL == nl->TheEmptyList())
{
regionNL = nl->OneElemList(faceNL);
regionNLLast = regionNL;
}
else
{
regionNLLast = nl->Append(regionNLLast, faceNL);
}
faceNL = nl->TheEmptyList();
currFace = hs.attr.faceno;
currCycle = hs.attr.cycleno;
RCopy->Get( i+1, hsnext);
if ((hs.GetLeftPoint() == hsnext.GetLeftPoint()) ||
((hs.GetLeftPoint() == hsnext.GetRightPoint())))
{
outputP = hs.GetRightPoint();
left = false;
leftoverP = hs.GetLeftPoint();
}
else
if ((hs.GetRightPoint() == hsnext.GetLeftPoint()) ||
((hs.GetRightPoint() == hsnext.GetRightPoint())))
{
outputP = hs.GetLeftPoint();
left = true;
leftoverP = hs.GetRightPoint();
}
else
{
cerr << "\n" << __PRETTY_FUNCTION__
<< ": Wrong data format --- "
<< "discontiguous segments in cycle!" << endl
<< "\ths = " << hs << endl
<< "\thsnext = " << hsnext << endl;
return nl->SymbolAtom(Symbol::UNDEFINED());
}
if (Region2::outType == 0)
pointNL = OutPoint( RCopy, i, left );
if (Region2::outType == 1)
pointNL = OutPoint2( RCopy, i, left );
if (cycleNL == nl->TheEmptyList())
{
cycleNL = nl->OneElemList(pointNL);
cycleNLLast = cycleNL;
}
else
{
cycleNLLast = nl->Append(cycleNLLast, pointNL);
}
}
}
}
if (faceNL == nl->TheEmptyList())
{
faceNL = nl->OneElemList(cycleNL);
faceNLLast = faceNL;
}
else
{
faceNLLast = nl->Append(faceNLLast, cycleNL);
}
cycleNL = nl->TheEmptyList();
if (regionNL == nl->TheEmptyList())
{
regionNL = nl->OneElemList(faceNL);
regionNLLast = regionNL;
}
else
{
regionNLLast = nl->Append(regionNLLast, faceNL);
}
faceNL = nl->TheEmptyList();
ListExpr factorNL = nl->IntAtom(RCopy->GetScaleFactor());
RCopy->DeleteIfAllowed();
if (Region2::outType == 0)
return nl->TwoElemList(factorNL, regionNL);
if (Region2::outType == 1)
return regionNL;
return nl->TheEmptyList();
}
}
/*
1.1 ~InRegion2~
*/
Word
InRegion2(const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct )
{
if(listutils::isSymbol(instance,Symbol::UNDEFINED()))
{
Region2* r = new Region2(0);
r->SetDefined(false);
correct = true;
return SetWord(Address(r));
}
int syntaxtyp = 0;
int scale = 0;
ListExpr regNL;
if (nl->ListLength(instance) == 2 &&
nl->AtomType(nl->First(instance)) == IntType)
{
syntaxtyp = 1;
scale = nl->IntValue(nl->First(instance));
regNL = nl->Second(instance);
}
else if ( nl->AtomType(instance) == NoAtom )
{
syntaxtyp = 2;
regNL = instance;
}
else
{
correct = false;
return SetWord(Address(0));
}
vector<vector<Reg2PrecisePoint> > cycles;
while (!nl->IsEmpty(regNL))
{
ListExpr faceNL = nl->First(regNL);
regNL = nl->Rest(regNL);
if (nl->AtomType(faceNL)!=NoAtom)
{
correct = false;
return SetWord(Address(0));
}
bool firstCycle = true;
Rectangle<2> faceRect;
while (!nl->IsEmpty(faceNL))
{
vector<Reg2PrecisePoint> cycle;
ListExpr cycleNL = nl->First(faceNL);
faceNL = nl->Rest(faceNL);
if (nl->AtomType(cycleNL)!=NoAtom)
{
correct=false;
return SetWord(Address(0));
}
Reg2PrecisePoint firstPoint;
bool fp = true;
Rectangle<2> currentBB;
while (!nl->IsEmpty(cycleNL))
{
ListExpr pointNL = nl->First(cycleNL);
cycleNL = nl->Rest(cycleNL);
mpq_class preciseX(0);
mpq_class preciseY(0);
Reg2PrecisePoint p;
if ( syntaxtyp == 1 )
{
if (nl->ListLength(pointNL) != 3
|| !nl->IsAtom(nl->First(pointNL))
|| !nl->IsAtom(nl->Second(pointNL))
|| nl->AtomType(nl->First(pointNL)) != IntType
|| nl->AtomType(nl->Second(pointNL)) != IntType)
{
correct = false;
return SetWord(Address(0));
}
if (nl->ListLength(nl->Third(pointNL)) == 2
&& nl->IsAtom(nl->First(nl->Third(pointNL)))
&& nl->AtomType(nl->First(nl->Third(pointNL)))
== TextType
&& nl->IsAtom(nl->Second(nl->Third(pointNL)))
&& nl->AtomType(nl->Second(nl->Third(pointNL)))
== TextType )
{
textTypeToGmpType1(nl->First(nl->Third(pointNL)),
preciseX);
textTypeToGmpType1(nl->Second(nl->Third(pointNL)),
preciseY);
}
mpq_class prX = mpq_class(preciseX
+ nl->IntValue(nl->First(pointNL)));
mpq_class prY = mpq_class(preciseY
+ nl->IntValue(nl->Second(pointNL)));
if (overflowAsInt(prX, prY, scale))
{
cerr << "Integer Overflow of the Values "
<< nl->ToString(pointNL) << endl;
cerr << "Please use a bigger scale factor!" << endl;
correct = false;
return SetWord(Address(0));
}
p = Reg2PrecisePoint(
preciseX,
nl->IntValue(nl->First(pointNL)),
preciseY,
nl->IntValue(nl->Second(pointNL)), scale);
}
else if ( syntaxtyp == 2 )
{
if(nl->ListLength(pointNL)!=2){
correct = false;
return SetWord(Address(0));
}
if ( listutils::isNumeric(nl->First(pointNL)) &&
listutils::isNumeric(nl->Second(pointNL)) )
{
syntaxtyp = 3;
preciseX = D2MPQ(listutils::getNumValue(
nl->First(pointNL)));
preciseY = D2MPQ(listutils::getNumValue(
nl->Second(pointNL)));
if (overflowAsInt(preciseX, preciseY, scale))
{
cerr << "Integer Overflow of the Values "
<< nl->ToString(pointNL) << endl;
cerr << "Please use a bigger scale factor!" << endl;
correct = false;
return SetWord(Address(0));
}
p = Reg2PrecisePoint(preciseX, preciseY);
}
else if ( nl->AtomType(nl->First(pointNL)) == TextType &&
nl->AtomType(nl->Second(pointNL)) == TextType )
{
syntaxtyp = 4;
textTypeToGmpType2(nl->First(pointNL), preciseX);
textTypeToGmpType2(nl->Second(pointNL), preciseY);
if (overflowAsInt(preciseX, preciseY, scale))
{
cerr << "Integer Overflow of the Values "
<< nl->ToString(pointNL) << endl;
cerr << "Please use a bigger scale factor!" << endl;
correct = false;
return SetWord(Address(0));
}
p = Reg2PrecisePoint(preciseX, preciseY);
}
else
{
correct = false;
return SetWord(Address(0));
}
}
else if ( syntaxtyp == 3 )
{
if(nl->ListLength(pointNL)!=2){
correct = false;
return SetWord(Address(0));
}
if ( listutils::isNumeric(nl->First(pointNL)) &&
listutils::isNumeric(nl->Second(pointNL)) )
{
preciseX = D2MPQ(listutils::getNumValue(
nl->First(pointNL)));
preciseY = D2MPQ(listutils::getNumValue(
nl->Second(pointNL)));
}
if (overflowAsInt(preciseX, preciseY, scale))
{
cerr << "Integer Overflow of the Values "
<< nl->ToString(pointNL) << endl;
cerr << "Please use a bigger scale factor!" << endl;
correct = false;
return SetWord(Address(0));
}
p = Reg2PrecisePoint(preciseX, preciseY);
}
else if ( syntaxtyp == 4 )
{
if(nl->ListLength(pointNL)!=2){
correct = false;
return SetWord(Address(0));
}
if ( nl->AtomType(nl->First(pointNL)) == TextType &&
nl->AtomType(nl->Second(pointNL)) == TextType )
{
textTypeToGmpType2(nl->First(pointNL), preciseX);
textTypeToGmpType2(nl->Second(pointNL), preciseY);
}
if (overflowAsInt(preciseX, preciseY, scale))
{
cerr << "Integer Overflow of the Values "
<< nl->ToString(pointNL) << endl;
cerr << "Please use a bigger scale factor!" << endl;
correct = false;
return SetWord(Address(0));
}
p = Reg2PrecisePoint(preciseX, preciseY);
}
cycle.push_back(p);
if (fp)
{
fp = false;
firstPoint = p;
currentBB = p.BoundingBox();
}
else
{
currentBB = currentBB.Union(p.BoundingBox());
}
}
if ( firstPoint != cycle[cycle.size()-1] )
{
cycle.push_back(firstPoint);
}
if (firstCycle || !faceRect.Contains(currentBB))
{
if ( !getDir2(cycle) )
{
reverseCycle2(cycle);
}
firstCycle = false;
faceRect = currentBB;
}
else
{
if (getDir2(cycle) )
{
reverseCycle2(cycle);
}
}
cycles.push_back(cycle);
}
}
Region2* res = buildRegion2(scale, cycles);
correct = res!=0;
return SetWord(res);
}
/*
1.1 ~CreateRegion2~
*/
Word
CreateRegion2( const ListExpr typeInfo )
{
return (SetWord( new Region2( 0 ) ));
}
/*
1.1 ~DeleteRegion2~
*/
void
DeleteRegion2( const ListExpr typeInfo, Word& w )
{
Region2 *r = (Region2 *)w.addr;
r->Destroy();
r->DeleteIfAllowed(false);
w.addr = 0;
}
/*
1.1 ~OpenRegion2~
*/
bool
OpenRegion2( SmiRecord& valueRecord,
size_t& offset,
const ListExpr typeInfo,
Word& value )
{
Region2 *r = (Region2*)Attribute::Open( valueRecord,
offset,
typeInfo );
value = SetWord( r );
return true;
}
/*
1.1 ~SaveRegion2~
*/
bool
SaveRegion2( SmiRecord& valueRecord,
size_t& offset,
const ListExpr typeInfo,
Word& value )
{
Region2 *r = (Region2 *)value.addr;
Attribute::Save( valueRecord, offset, typeInfo, r );
return true;
}
/*
1.1 ~CloseRegion2~
*/
void
CloseRegion2( const ListExpr typeInfo, Word& w )
{
((Region2 *)w.addr)->DeleteIfAllowed();
w.addr = 0;
}
/*
1.1 ~CloneRegion2~
*/
Word
CloneRegion2( const ListExpr typeInfo, const Word& w )
{
Region2 *r = new Region2( *((Region2 *)w.addr) );
return SetWord( r );
}
/*
1.1 ~SizeOfRegion2~
*/
static int SizeOfRegion2()
{
return sizeof(Region2);
}
/*
1.1 ~CheckRegion2~
*/
bool
CheckRegion2( ListExpr type, ListExpr& errorInfo )
{
return (nl->IsEqual( type, Region2::BasicType() ));
}
/*
1.1 TypeConstructor ~regionp~
*/
TypeConstructor regionp(
Region2::BasicType(),
Region2Property,
OutRegion2, InRegion2,
0, 0,
CreateRegion2, DeleteRegion2,
OpenRegion2, SaveRegion2,
CloseRegion2, CloneRegion2,
Region2::Cast,
SizeOfRegion2,
CheckRegion2 );
/*
1 Operators of the Region2Algebra
1.1 Helper function ~simpleSelect~
*/
static int simpleSelect(ListExpr args)
{
return 0;
}
/*
1.1 Operator setscalefactor
*/
static ListExpr SetScaleTypeMap(ListExpr args)
{
if (nl->ListLength(args) != 2){
ErrorReporter::ReportError(
"Invalid number of arguments: "
"operator expects 2 arguments");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->First(args),Region2::BasicType())){
ErrorReporter::ReportError(
"Region2 as first argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->Second(args),CcInt::BasicType())){
ErrorReporter::ReportError(
"Type Integer as second argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
return nl->SymbolAtom(Region2::BasicType());
}
static int SetScaleValueMap(Word* args, Word& result, int message,
Word& local, Supplier s)
{
result = qp->ResultStorage(s);
Region2* reg = (Region2*) args[0].addr;
int newScale = ((CcInt*)args[1].addr)->GetIntval();
Region2 reg2(*reg);
if (!reg2.SetScaleFactor(newScale))
{
cerr << "Scalefactor " << newScale << " is too big!!" << endl;
((Region2*)result.addr)->SetDefined( false );
return 0;
}
((Region2*)result.addr)->CopyFrom(&reg2);
return 0;
}
static const string setscalespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>regionp x int -> regionp</text--->"
"<text>setscalefactor( _, _)</text--->"
"<text>Changes the scale factor for a given regionp.\n"
"The new scale factor is 10^(scale), this means that "
"the integer value is the exponent to the base 10 of "
"the new factor.\n"
"If the scalefactor is too big resulting in an integer "
"overflow, an error is reported.</text--->"
"<text>query setscalefactor(reg2, 12)</text--->) )";
static Operator setscale("setscalefactor",
setscalespec,
SetScaleValueMap,
simpleSelect,
SetScaleTypeMap);
/*
1.1 Operator setregionpoutstlye
*/
static ListExpr SetOutStyleTypeMap(ListExpr args)
{
if (nl->ListLength(args) != 1){
ErrorReporter::ReportError(
"Invalid number of arguments: "
"operator expects 1 argument");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
ListExpr second = nl->First(args);
if(!nl->IsEqual(second, CcInt::BasicType())){
return listutils::typeError(
"The argument must be of type int.");
}
return (nl->SymbolAtom(CcBool::BasicType()));
}
static int SetOutStyleValueMap(Word* args, Word& result, int message,
Word& local, Supplier s)
{
result = qp->ResultStorage(s);
unsigned style = ((CcInt*)args[0].addr)->GetIntval();
CcBool *res = (CcBool*) result.addr;
bool sc = Region2::SetOutType(style);
res->Set( true, sc );
return 0;
}
static const string setoutstylespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" ( <text>int -> bool</text--->"
" <text>setregionpoutstyle( _)</text--->"
" <text>Changes the style of the out function,"
" how the points are printed. "
" 0 (default) is <int int <precisePart> > like"
" the standard constructor and 1 is <text text> "
"representing real values with arbitrary precision."
"</text---> <text>query setregionpoutstyle(1)"
"</text--->) )";
static Operator setoutstyle("setregionpoutstyle",
setoutstylespec,
SetOutStyleValueMap,
simpleSelect,
SetOutStyleTypeMap);
/*
1.1 Operator isempty
*/
ListExpr isemptyTypeMap(ListExpr args)
{
if ( nl->IsEqual(nl->First(args),Region2::BasicType()))
return (nl->SymbolAtom( CcBool::BasicType() ));
ErrorReporter::ReportError("Region2 as argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int isemptyValueMap(Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
const Region2* r = static_cast<const Region2*>(args[0].addr);
((CcBool *)result.addr)->Set(true, r->IsEmpty());
return 0;
}
const string isemptyspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
"( <text>regionp -> bool</text--->"
"<text>isempty ( _ )</text--->"
"<text>Returns TRUE if the value is undefined or empty."
" The result is always defined!</text--->"
"<text>query isempty ( regionp )</text--->"
") )";
static Operator isempty ("isempty",
isemptyspec,
isemptyValueMap,
simpleSelect,
isemptyTypeMap );
/*
1.1 Operator intersects
*/
ListExpr intersectsTypeMap( ListExpr args )
{
if ( nl->IsEqual(nl->First(args),Region2::BasicType())
&& nl->IsEqual(nl->Second(args),Region2::BasicType()))
return (nl->SymbolAtom( CcBool::BasicType() ));
ErrorReporter::ReportError(
"Region2 as first and second argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int intersectsValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Region2* r1 = static_cast<Region2*>(args[0].addr);
Region2* r2 = static_cast<Region2*>(args[1].addr);
if( r1->IsDefined() && r2->IsDefined() )
((CcBool *)result.addr)->Set( true, r1->Intersects( *r2 ) );
else
((CcBool *)result.addr)->SetDefined( false );
return 0;
}
const string intersectsspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
"( <text>regionp x regionp -> bool </text--->"
"<text>_ intersects _</text--->"
"<text>TRUE, iff both regionps intersect.</text--->"
"<text>query reg21 intersects reg26</text--->"
") )";
static Operator intersects ( "intersects",
intersectsspec,
intersectsValueMap,
simpleSelect,
intersectsTypeMap );
/*
1.1 Operator inside
*/
int insideValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Region2* r1 = static_cast<Region2*>(args[0].addr);
Region2* r2 = static_cast<Region2*>(args[1].addr);
if( r1->IsDefined() && r2->IsDefined() )
((CcBool *)result.addr)->Set( true, r1->Inside( *r2 ) );
else
((CcBool *)result.addr)->SetDefined( false );
return 0;
}
const string insidespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
"( <text>regionp x regionp -> bool</text--->"
"<text>_ inside _</text--->"
"<text>TRUE iff the first regionp is inside the second regionp."
"</text---><text>query reg23 inside reg25</text--->"
") )";
static Operator inside ( "inside",
insidespec,
insideValueMap,
simpleSelect,
intersectsTypeMap );
/*
1.1 Operator adjacent
*/
int adjacentValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Region2* r1 = static_cast<Region2*>(args[0].addr);
Region2* r2 = static_cast<Region2*>(args[1].addr);
if( r1->IsDefined() && r2->IsDefined() )
((CcBool *)result.addr)->Set( true, r1->Adjacent( *r2 ) );
else
((CcBool *)result.addr)->SetDefined( false );
return 0;
}
const string adjacentspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
"( <text>regionp x regionp -> bool</text--->"
"<text>_ adjacent _</text--->"
"<text>TRUE, iff both regionps are adjacent.</text--->"
"<text>query reg21 adjacent reg22</text--->"
") )";
static Operator adjacent ( "adjacent",
adjacentspec,
adjacentValueMap,
simpleSelect,
intersectsTypeMap );
/*
1.1 Operator overlaps
*/
int overlapsValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Region2* r1 = static_cast<Region2*>(args[0].addr);
Region2* r2 = static_cast<Region2*>(args[1].addr);
if( r1->IsDefined() && r2->IsDefined() )
((CcBool *)result.addr)->Set( true,r1->Overlaps( *r2 ) );
else
((CcBool *)result.addr)->SetDefined( false );
return 0;
}
const string overlapsspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
"( <text>regionp x regionp -> bool</text--->"
"<text>_ overlaps _</text--->"
"<text>TRUE, iff both regionp objects overlap each other."
"</text---><text>query reg22 overlap reg24</text--->"
") )";
static Operator overlaps ( "overlaps",
overlapsspec,
overlapsValueMap,
simpleSelect,
intersectsTypeMap );
/*
1.1 Operator no[_]components
*/
ListExpr nocomponentsTypeMap(ListExpr args)
{
if ( nl->IsEqual(nl->First(args),Region2::BasicType()))
return (nl->SymbolAtom( CcInt::BasicType() ));
ErrorReporter::ReportError("Region2 as argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int nocomponentsValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
const Region2* r = static_cast<const Region2*>(args[0].addr);
if( r->IsDefined() )
((CcInt *)result.addr)->Set( true, r->NoComponents() );
else
((CcInt *)result.addr)->Set( false, 0 );
return 0;
}
const string nocomponentsspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp -> int</text--->"
"<text>no_components( _ )</text--->"
"<text>return the number of components, "
"here: the number of faces of a regionp object.</text--->"
"<text>query no_components(region)</text--->"
") )";
static Operator nocomponents ( "no_components",
nocomponentsspec,
nocomponentsValueMap,
simpleSelect,
nocomponentsTypeMap );
/*
1.1 Operator no[_]segments
*/
int nosegmentsValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
const Region2* r = static_cast<const Region2*>(args[0].addr);
if( r->IsDefined() )
((CcInt *)result.addr)->Set( true, r->Size() );
else
((CcInt *)result.addr)->Set( false, 0 );
return 0;
}
const string nosegmentsspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp -> int</text--->"
"<text>no_segments( _ )</text--->"
"<text>return the number of half segments of a regionp object."
"</text---><text>query no_segments(region)</text--->"
") )";
static Operator nosegments ( "no_segments",
nosegmentsspec,
nosegmentsValueMap,
simpleSelect,
nocomponentsTypeMap );
/*
1.1 Operator bbox
*/
ListExpr reg2bboxTypeMap( ListExpr args )
{
if ( nl->IsEqual(nl->First(args),Region2::BasicType()))
return (nl->SymbolAtom( Rectangle<2>::BasicType() ));
ErrorReporter::ReportError("Region2 as argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int reg2bboxValueMap(Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Rectangle<2>* box = static_cast<Rectangle<2>* >(result.addr);
const Region2* r = static_cast<const Region2*>(args[0].addr);
if ( !r->IsDefined() )
{
box->SetDefined(false);
} else {
(*box) = r->BoundingBox();
}
return 0;
}
const string reg2bboxspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp -> rect</text--->"
"<text>bbox( _ )</text--->"
"<text>Returns the bounding box of a regionp object.</text--->"
"<text>query bbox(reg22)</text--->"
") )";
static Operator reg2bbox ( "bbox",
reg2bboxspec,
reg2bboxValueMap,
simpleSelect,
reg2bboxTypeMap );
/*
1.1 Operator translate
*/
ListExpr translateTypeMap( ListExpr args )
{
ListExpr arg1, arg2;
if ( nl->ListLength( args ) == 2 )
{
arg1 = nl->First( args );
arg2 = nl->Second( args );
if( nl->IsEqual(arg1, Region2::BasicType()) &&
nl->IsEqual(nl->First( arg2 ), CcReal::BasicType()) &&
nl->IsEqual(nl->Second( arg2 ), CcReal::BasicType()))
return (nl->SymbolAtom( Region2::BasicType() ));
}
ErrorReporter::ReportError("First argument as Region2 required, "
"second and third as Real!");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int translateValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Region2 *cr = (Region2 *)args[0].addr,
*pResult = (Region2 *)result.addr;
pResult->Clear();
Supplier son = qp->GetSupplier( args[1].addr, 0 );
Word t;
qp->Request( son, t );
const CcReal *tx = ((CcReal *)t.addr);
son = qp->GetSupplier( args[1].addr, 1 );
qp->Request( son, t );
const CcReal *ty = ((CcReal *)t.addr);
if( cr->IsDefined() && tx->IsDefined() && ty->IsDefined() ) {
const double txval = (double)(tx->GetRealval()),
tyval = (double)(ty->GetRealval());
cr->Translate( txval, tyval, *pResult );
}
else
((Region2*)result.addr)->SetDefined( false );
return 0;
}
const string translatespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp x real x real -> regionp</text--->"
"<text>_ translate [ _, _ ]</text--->"
"<text>move the object parallely for some distance.\n"
"If the distances are too big resulting in an integer "
"overflow, an error is reported.</text--->"
"<text>query regionp1 translate[3.5, 15.1]</text--->"
") )";
static Operator reg2translate ( "translate",
translatespec,
translateValueMap,
simpleSelect,
translateTypeMap );
/*
1.1 Operator scale
*/
ListExpr scaleTypeMap(ListExpr args)
{
if(nl->ListLength(args)!=2){
return listutils::typeError(
"Operator scale requires two arguments");
}
ListExpr arg1 = nl->First(args);
ListExpr arg2 = nl->Second(args);
if(!(nl->IsEqual(arg2 , CcReal::BasicType()))){
return listutils::typeError("expects real as 2nd argument");
}
if(nl->IsEqual(arg1,Region2::BasicType()))
return nl->SymbolAtom(Region2::BasicType());
return listutils::typeError(
"Expected first argument to be of regionp");
}
int scaleValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage(s);
Region2 *R = (Region2*) args[0].addr;
CcReal *factor = (CcReal*) args[1].addr;
Region2 *res = (Region2*) result.addr;
if( !R->IsDefined() || !factor->IsDefined()
|| R->factorOverflow(factor->GetRealval()) )
{
res->SetDefined(false);
}
else
{
res->Clear();
res->SetDefined(true);
double f = factor->GetRealval();
if(!R->IsEmpty()){
res->StartBulkLoad();
int size = R->Size();
Reg2PreciseHalfSegment hs;
for(int i=0;i<size;i++){
R->Get(i,hs);
hs.Scale(f, f);
if ( overflowAsInt(hs.GetLeftPoint().x, hs.GetLeftPoint().y,
R->GetScaleFactor())
|| overflowAsInt(hs.GetRightPoint().x, hs.GetRightPoint().y,
R->GetScaleFactor()) )
{
cerr << "Overflow of Int values: Factor "
<< f << " is too big!!" << endl;
res->SetDefined( false );
return 0;
}
(*res) += hs;
}
res->SetNoComponents( R->NoComponents() );
res->SetScaleFactor( R->GetScaleFactor() );
res->EndBulkLoad( false, false, false, false, true );
}
}
return 0;
}
const string scalespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp x real -> regionp</text--->"
"<text>_ scale [ _ ] </text--->"
"<text>scales a regionp object by the given factor.\n"
"If the factor is too big resulting in an integer "
"overflow, an error is reported.</text--->"
"<text>query regionp1 scale[10.0]</text--->"
") )";
static Operator scale ( "scale",
scalespec,
scaleValueMap,
simpleSelect,
scaleTypeMap );
/*
1.1 Operator scale2
*/
ListExpr scale2TypeMap(ListExpr args)
{
if(nl->ListLength(args)!=3){
return listutils::typeError(
"Operator scale2 requires three arguments");
}
ListExpr arg1 = nl->First(args);
ListExpr arg2 = nl->Second(args);
if(!(nl->IsEqual(arg2 , CcReal::BasicType()))){
return listutils::typeError("expects real as 2nd argument");
}
ListExpr arg3 = nl->Third(args);
if(!(nl->IsEqual(arg3 , CcReal::BasicType()))){
return listutils::typeError("expects real as 3rd argument");
}
if(nl->IsEqual(arg1,Region2::BasicType()))
return nl->SymbolAtom(Region2::BasicType());
return listutils::typeError(
"Expected first argument to be of regionp");
}
int scale2ValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage(s);
Region2 *R = (Region2*) args[0].addr;
CcReal *xfactor = (CcReal*) args[1].addr;
CcReal *yfactor = (CcReal*) args[2].addr;
Region2 *res = (Region2*) result.addr;
if( !R->IsDefined() || !xfactor->IsDefined() || !yfactor->IsDefined()
|| R->factorOverflow(xfactor->GetRealval(), yfactor->GetRealval()) )
{
res->SetDefined(false);
}
else
{
res->Clear();
res->SetDefined(true);
double xf = xfactor->GetRealval();
double yf = yfactor->GetRealval();
if(!R->IsEmpty()){
res->StartBulkLoad();
int size = R->Size();
Reg2PreciseHalfSegment hs;
for(int i=0;i<size;i++){
R->Get(i,hs);
hs.Scale(xf, yf);
if ( overflowAsInt(hs.GetLeftPoint().x, hs.GetRightPoint().x,
R->GetScaleFactor()) )
{
cerr << "Overflow of Int values: x-Factor "
<< xf << " is too big!!" << endl;
res->SetDefined( false );
return 0;
}
if ( overflowAsInt(hs.GetLeftPoint().y, hs.GetRightPoint().y,
R->GetScaleFactor()) )
{
cerr << "Overflow of Int values: y-Factor "
<< yf << " is too big!!" << endl;
res->SetDefined( false );
return 0;
}
(*res) += hs;
}
res->SetNoComponents( R->NoComponents() );
res->SetScaleFactor( R->GetScaleFactor() );
res->EndBulkLoad( false, false, false, false, true );
}
}
return 0;
}
const string scale2spec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp x real x real -> regionp</text--->"
"<text>_ scale2 [ _, _ ] </text--->"
"<text>scales a regionp object by the given factors in x-"
" and y-direction differently.\n"
"If the factors are too big resulting in an integer "
"overflow, an error is reported.</text--->"
"<text>query regionp1 scale[10.0, 1.0]</text--->"
") )";
static Operator scale2 ( "scale2",
scale2spec,
scale2ValueMap,
simpleSelect,
scale2TypeMap );
/*
1.1 Operator components
*/
ListExpr componentsTypeMap( ListExpr args )
{
if ( nl->IsEqual(nl->First(args),Region2::BasicType()))
return nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()),
nl->SymbolAtom(Region2::BasicType()) );
ErrorReporter::ReportError("Region2 as argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
struct ComponentsLocalInfo
{
vector<Region2*> components;
vector<Region2*>::iterator iter;
};
int componentsValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
ComponentsLocalInfo *localInfo;
switch( message )
{
case OPEN:
// IsEmpty() subsumes undef
if( !((Region2*)args[0].addr)->IsEmpty() ){
localInfo = new ComponentsLocalInfo();
((Region2*)args[0].addr)->Components(
localInfo->components );
localInfo->iter = localInfo->components.begin();
local.setAddr( localInfo );
} else {
local.setAddr( 0 );
}
return 0;
case REQUEST:
if( !local.addr ) {
return CANCEL;
}
localInfo = (ComponentsLocalInfo*)local.addr;
if( localInfo->iter == localInfo->components.end() )
return CANCEL;
result.setAddr( *localInfo->iter++ );
return YIELD;
case CLOSE:
if(local.addr)
{
localInfo = (ComponentsLocalInfo*)local.addr;
while( localInfo->iter != localInfo->components.end() )
{
delete *localInfo->iter++;
}
delete localInfo;
local.setAddr(0);
}
return 0;
}
return 0;
}
const string componentsspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )"
"( <text>regionp -> stream(regionp)</text--->"
"<text>components( _ )</text--->"
"<text>Returns the components of a region object "
"(the contained faces) as a stream."
"Both, empty and undefined objects result in empty stream."
"</text---><text>query components(reg21) count</text--->"
") )";
static Operator components ( "components",
componentsspec,
componentsValueMap,
simpleSelect,
componentsTypeMap );
/*
1.1 Operator getHoles
*/
ListExpr getholesTypeMap(ListExpr args)
{
if ( nl->IsEqual(nl->First(args),Region2::BasicType()))
return nl->SymbolAtom(Region2::BasicType());
ErrorReporter::ReportError("Region2 as argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int getholesValueMap(Word* args, Word& result, int message,
Word& local, Supplier s )
{
Region2* arg = (Region2*) args[0].addr;
result = qp->ResultStorage(s);
Region2* res = (Region2*) result.addr;
arg->getHoles(*res);
return 0;
}
const string getholesspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp -> regionp</text--->"
"<text>getHoles(_) </text--->"
"<text>Returns the holes of a region.</text--->"
"<text>query getHoles(reg22) </text--->"
") )";
static Operator getholes( "getHoles",
getholesspec,
getholesValueMap,
simpleSelect,
getholesTypeMap
);
/*
1.1 Operator region2regionp
*/
ListExpr region2regionpTypeMap( ListExpr args )
{
if ( nl->IsEqual(nl->First(args),Region::BasicType()) )
return (nl->SymbolAtom( Region2::BasicType() ));
ErrorReporter::ReportError("region as argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int region2regionpValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Region *r = (Region *)args[0].addr;
Region2 *res = (Region2*)result.addr;
*res = Region2( *r );
return 0;
}
const string region2regionpspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>region -> regionp</text--->"
"<text>_ region2regionp</text--->"
"<text>Converts a region object to a regionp object.\n"
"The predefined scale factor is 0, this means a factor "
"of 10^0 = 1, because the scale value is the exponent "
"to the base 10 of the overall factor.\n"
"If the point values are too big resulting in an integer "
"overflow, an error is reported.\n"
"In this case better use regiontoregionp.</text--->"
"<text>query [const region value ( (1 1 2 2)(3 3 4 4) )] "
"region2regionp </text--->) )";
static Operator region2regionp ( "region2regionp",
region2regionpspec,
region2regionpValueMap,
simpleSelect,
region2regionpTypeMap );
/*
1.1 Operator regiontoregionp
*/
ListExpr regiontoregionpTypeMap( ListExpr args )
{
if (nl->ListLength(args) != 2){
ErrorReporter::ReportError(
"Invalid number of arguments: "
"operator expects 2 arguments");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->First(args),Region::BasicType())){
ErrorReporter::ReportError(
"Region as first argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->Second(args),CcInt::BasicType())){
ErrorReporter::ReportError(
"Type Integer as second argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
return nl->SymbolAtom(Region2::BasicType());
}
int regiontoregionpValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Region *r = (Region *)args[0].addr;
int scale = ((CcInt *)args[1].addr)->GetIntval();
Region2 *res = (Region2*)result.addr;
*res = Region2( *r, scale);
return 0;
}
const string regiontoregionpspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>region x int -> regionp</text--->"
"<text>regiontoregionp (_, _)</text--->"
"<text>Converts a region object to a regionp object with "
"a scale of the given int value.\n"
"The scalefactor is 10^(scale), this means that "
"the integer value is the exponent to the base 10 of "
"the new factor.\n"
"If the scalefactor is too big resulting in an integer "
"overflow, an error is reported.</text--->"
"<text>query regiontoregionp([const region value ( (1 1 2 2)(3 3"
" 4 4) )], 2)</text--->) )";
static Operator regiontoregionp ( "regiontoregionp",
regiontoregionpspec,
regiontoregionpValueMap,
simpleSelect,
regiontoregionpTypeMap );
/*
1.1 Operator rect2regionp
*/
ListExpr rect2regionpTypeMap( ListExpr args )
{
if ( nl->IsEqual(nl->First(args),Rectangle<2>::BasicType()) )
return (nl->SymbolAtom( Region2::BasicType() ));
ErrorReporter::ReportError("Rectangle<2> as argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int rect2regionpValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Rectangle<2> *rect = (Rectangle<2> *)args[0].addr;
Region2 *res = (Region2*)result.addr;
*res = Region2( *rect );
return 0;
}
const string rect2regionpspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>rect -> regionp</text--->"
"<text>_ rect2regionp</text--->"
"<text>Converts a rect object to a regionp object.\n"
"The predefined scale factor is 0, this means a factor "
"of 10^0 = 1, because the scale value is the exponent "
"to the base 10 of the overall factor.\n"
"If the values are too big resulting in an integer "
"overflow, an error is reported.\n"
"In this case better use recttoregionp.</text--->"
"<text>query [const rect value (-100.0 200.0 -50.0 500.0)] "
"rect2regionp </text--->) )";
static Operator rect2regionp ( "rect2regionp",
rect2regionpspec,
rect2regionpValueMap,
simpleSelect,
rect2regionpTypeMap );
/*
1.1 Operator recttoregionp
*/
ListExpr recttoregionpTypeMap( ListExpr args )
{
if (nl->ListLength(args) != 2){
ErrorReporter::ReportError(
"Invalid number of arguments: "
"operator expects 2 arguments");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->First(args),Rectangle<2>::BasicType())){
ErrorReporter::ReportError(
"Rectangle<2> as first argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (!nl->IsEqual(nl->Second(args),CcInt::BasicType())){
ErrorReporter::ReportError(
"Type Integer as second argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
return nl->SymbolAtom(Region2::BasicType());
}
int recttoregionpValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Rectangle<2> *rect = (Rectangle<2> *)args[0].addr;
int scale = ((CcInt *)args[1].addr)->GetIntval();
Region2 *res = (Region2*)result.addr;
*res = Region2( *rect, scale );
return 0;
}
const string recttoregionpspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>rect x int -> regionp</text--->"
"<text>recttoregionp (_, _)</text--->"
"<text>Converts a rect object to a regionp object with "
"a scale of the given int value.\n"
"The scalefactor is 10^(scale), this means that "
"the integer value is the exponent to the base 10 of "
"the new factor.\n"
"If the scalefactor is too big resulting in an integer "
"overflow, an error is reported.</text--->"
"<text>query recttoregionp([const rect value (-100.0 200.0 "
"-50.0 500.0)], 2)</text--->) )";
static Operator recttoregionp ( "recttoregionp",
recttoregionpspec,
recttoregionpValueMap,
simpleSelect,
recttoregionpTypeMap );
/*
1.1 Operators area and size
*/
ListExpr areaTypeMap( ListExpr args )
{
if ( nl->IsEqual(nl->First(args),Region2::BasicType()) )
return (nl->SymbolAtom( CcReal::BasicType() ));
ErrorReporter::ReportError("Region2 as argument required");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
int areaValueMap( Word* args, Word& result, int message,
Word& local, Supplier s )
{
result = qp->ResultStorage( s );
Region2 *reg = (Region2 *)args[0].addr;
CcReal *res = (CcReal *)result.addr;
if( reg->IsDefined() )
res->Set( true, reg->Area() );
else
res->Set( false, 0.0 );
return 0;
}
const string areaspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp -> real</text--->"
"<text>area( _ )</text--->"
"<text>Returns the area of a regionp object as a real value."
"</text---><text> query area( reg22 )</text--->"
") )";
static Operator area ( "area",
areaspec,
areaValueMap,
simpleSelect,
areaTypeMap );
const string sizespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>regionp -> real</text--->"
"<text>size( _ )</text--->"
"<text>Returns the size of a regionp object as a real value."
"</text---><text> query size( reg22 )</text--->"
") )";
static Operator size ( "size",
sizespec,
areaValueMap,
simpleSelect,
areaTypeMap );
/*
1 Algebra creation
*/
class Region2Algebra : public Algebra
{
public:
Region2Algebra() : Algebra()
{
AddTypeConstructor( &regionp );
regionp.AssociateKind(Kind::DATA());
AddOperator(&setscale);
AddOperator(&setoutstyle);
AddOperator( &isempty );
AddOperator( &intersects );
AddOperator( &inside );
AddOperator( &adjacent );
AddOperator( &overlaps );
AddOperator( &nocomponents );
AddOperator( &nosegments );
AddOperator( &reg2bbox);
AddOperator( &reg2translate );
AddOperator( &scale );
AddOperator( &scale2 );
AddOperator( &components );
AddOperator( &getholes );
AddOperator( &region2regionp );
AddOperator( &regiontoregionp );
AddOperator( &rect2regionp );
AddOperator( &recttoregionp );
AddOperator( &size );
AddOperator( &area );
}
~Region2Algebra() {};
};
extern "C"
Algebra*
InitializeRegion2Algebra( NestedList* nlRef, QueryProcessor* qpRef )
{
nl = nlRef;
qp = qpRef;
return (new Region2Algebra());
}