Files
secondo/Algebras/Precise/PrecSecTypes.cpp

2159 lines
55 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
----
This file is part of SECONDO.
Copyright (C) 2013,
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
----
1 Includes and global variables
*/
#include "PrecSecTypes.h"
#include "Algebras/Spatial/SpatialAlgebra.h"
#include "StringUtils.h"
#include "HsTools.h"
#include "PrecTools.h"
#include "MMRTree.h"
using namespace std;
class MPrecPointComp{
public:
bool operator()(const MPrecPoint& p1, const MPrecPoint& p2){
return p1.compareTo(p2) < 0;
}
};
class LogicCompare{
public:
bool operator()(const MPrecHalfSegment& hs1, const MPrecHalfSegment& hs2){
AttrType a1 = hs1.attributes;
AttrType a2 = hs2.attributes;
if(a1.faceno < a2.faceno) return true;
if(a1.faceno > a2.faceno) return false;
if(a1.cycleno < a2.cycleno) return true;
if(a1.cycleno > a2.cycleno) return false;
if(a1.edgeno < a2.edgeno) return true;
if(a1.edgeno > a2.edgeno) return false;
return false;
}
};
/*
2 Auxiliary functions
*/
ListExpr toListExpr(const MPrecCoordinate& x){
if(!x.hasFracPart()){
return listutils::getInt64List(x.getGridCoord());
}
return nl->TwoElemList(
listutils::getInt64List(x.getGridCoord()),
nl->TextAtom(x.getFracAsText()));
}
ListExpr toListExpr(const MPrecPoint& p){
return nl->TwoElemList( toListExpr(p.getX()),
toListExpr(p.getY()));
}
ListExpr toListExpr(const MPrecHalfSegment& hs){
return nl->TwoElemList( toListExpr(hs.getLeftPoint()),
toListExpr(hs.getRightPoint()));
}
bool readFrom(ListExpr le, MPrecCoordinate& result, bool includeScale,
const uint32_t _scale){
int64_t intPart=0;
uint32_t scale = _scale;
if(includeScale){
if(!nl->HasLength(le,2)){
return false;
}
ListExpr sl = nl->First(le);
le = nl->Rest(le);
if(nl->AtomType(sl)!=IntType){
return false;
}
scale = nl->IntValue(sl);
if(scale <=0){
return false;
}
}
if(nl->AtomType(le)==IntType){
result = MPrecCoordinate((int) nl->IntValue(le), scale);
return true;
}
if(nl->HasLength(le,1)){
if(!listutils::decodeInt64(nl->First(le),intPart)){
return false;
}
result = MPrecCoordinate(intPart, scale);
return true;
}
if(!nl->HasLength(le,2)){
return false;
}
if(!listutils::decodeInt64(nl->First(le),intPart)){
return false;
}
if(nl->AtomType(nl->Second(le)) != TextType){
return false;
}
try{
result.set(intPart, nl->Text2String(nl->Second(le)), scale);
return true;
} catch(...){
return false;
}
}
bool readPoint(ListExpr le, MPrecPoint& result,
bool includeScale, const uint32_t _scale){
uint32_t scale = _scale;
if(includeScale){
if(!nl->HasLength(le,2)){
return false;
}
ListExpr sl = nl->First(le);
le = nl->Second(le);
if(nl->AtomType(sl)!=IntType){
return false;
}
scale = nl->IntValue(sl);
if(scale <=0){
return false;
}
}
if(!nl->HasLength(le,2)){
return false;
}
MPrecCoordinate x(0);
MPrecCoordinate y(0);
if(!readFrom(nl->First(le),x,false,scale) ||
!readFrom(nl->Second(le),y,false,scale)){
return false;
}
result.set(x,y);
return true;
}
void enlarge(Rectangle<2>& box, const MPrecPoint& p){
double x = p.getX().toDouble();
double y = p.getY().toDouble();
if(!box.IsDefined()){
double min[] = {x,y};
double max[] = {x,y};
box.Set(true,min,max);
return;
}
double MIN[] = {std::min(x,box.MinD(0)), std::min(y,box.MinD(1))};
double MAX[] = {std::max(x,box.MaxD(0)), std::max(y,box.MaxD(1))};
box.Set(true,MIN,MAX);
}
double getQDistance(const Rectangle<2>& rect,
const MPrecPoint& p ) {
double x = p.getX().toDouble();
double y = p.getY().toDouble();
double x1 = rect.MinD(0);
double x2 = rect.MaxD(0);
double y1 = rect.MinD(0);
double y2 = rect.MaxD(0);
if(x<x1){
if(y<y1){
return ( (x1-x)*(x1-x) + (y1-y)*(y1-y));
}
if(y>y2){
return ( (x1-x)*(x1-x) + (y2-y)*(y2-y));
}
return (x1-x) * (x1-x);
}
if(x>x2){
if(y<y1){
return ( (x2-x)*(x2-x) + (y1-y)*(y1-y));
}
if(y>y2){
return ( (x2-x)*(x2-x) + (y2-y)*(y2-y));
}
return (x-x2)*(x-x2);
}
if(y<y1){
return (y1-y)*(y1-y);
}
if(y>y2){
return (y - y2)*(y-y2);
}
return 0;
}
bool intersects(const Rectangle<2>& rect,
const MPrecPoint& p){
double x1 = rect.MinD(0);
double y1 = rect.MinD(1);
MPrecCoordinate x = p.getX();
MPrecCoordinate y = p.getY();
if(x<x1 || y < y1){
return false;
}
double x2 = rect.MaxD(0);
double y2 = rect.MaxD(1);
if(x>x2 || y > y2){
return false;
}
return true;
}
ListExpr getCycleList(const vector<MPrecHalfSegment>& v, size_t& pos){
assert(pos < v.size()-2); // we need at least 3 segments to build a cycle
MPrecHalfSegment hs1 = v[pos];
int ffaceno = hs1.attributes.faceno; // facno of first segment
int fcycleno = hs1.attributes.cycleno; // facno of second segment
MPrecHalfSegment hs2 = v[pos+1];
assert(ffaceno == hs2.attributes.faceno);
assert(fcycleno == hs2.attributes.cycleno);
MPrecPoint p1l = hs1.getLeftPoint();
MPrecPoint p1r = hs1.getRightPoint();
MPrecPoint p2l = hs2.getLeftPoint();
MPrecPoint p2r = hs2.getRightPoint();
ListExpr cycle=nl->TheEmptyList();
ListExpr last=nl->TheEmptyList();
MPrecPoint lastPoint(0,0);
if(p1l==p2l){
cycle = nl->OneElemList( toListExpr(p1r));
last = cycle;
last = nl->Append( last, toListExpr(p1l));
last = nl->Append( last, toListExpr(p2r));
lastPoint = p2r;
} else if(p1l == p2r){
cycle = nl->OneElemList( toListExpr(p1r));
last = cycle;
last = nl->Append( last, toListExpr(p1l));
last = nl->Append( last, toListExpr(p2l));
lastPoint = p2l;
} else if(p1r == p2l){
cycle = nl->OneElemList( toListExpr(p1l));
last = cycle;
last = nl->Append( last, toListExpr(p1r));
last = nl->Append( last, toListExpr(p2r));
lastPoint = p2r;
} else if(p1r==p2r){
cycle = nl->OneElemList( toListExpr(p1l));
last = cycle;
last = nl->Append( last, toListExpr(p1r));
last = nl->Append( last, toListExpr(p2l));
lastPoint = p2l;
}
pos = pos + 2;
hs1 = v[pos];
while( pos < v.size() && hs1.attributes.cycleno == fcycleno &&
hs1.attributes.faceno==ffaceno){
p1l = hs1.getLeftPoint();
p1r = hs1.getRightPoint();
if(p1l==lastPoint){
lastPoint = p1r;
} else {
assert(p1r == lastPoint);
lastPoint = p1l;
}
last = nl->Append(last, toListExpr(lastPoint));
pos++;
if(pos<v.size()){
hs1 = v[pos];
}
}
return cycle;
}
ListExpr getFaceList(const vector<MPrecHalfSegment>& v, size_t& pos){
assert(pos < v.size());
MPrecHalfSegment hs = v[pos];
int ffaceno = hs.attributes.faceno;
bool first = true;
int faceno = ffaceno;
ListExpr cycles=nl->TheEmptyList();
ListExpr last = nl->TheEmptyList();
while(pos < v.size() && faceno==ffaceno){
ListExpr cycle = getCycleList(v,pos);
if(first){
cycles = nl->OneElemList(cycle);
last = cycles;
first = false;
} else {
last = nl->Append(last,cycle);
}
if(pos<v.size()){
faceno = v[pos].attributes.faceno;
}
}
return cycles;
}
ListExpr getRegionList(vector<MPrecHalfSegment>& v){
if(v.empty()){
return nl->TheEmptyList();
}
LogicCompare cmp;
sort(v.begin(), v.end(), cmp);
ListExpr faces=nl->TheEmptyList();
ListExpr last=nl->TheEmptyList();
size_t pos = 0;
bool first = true;
while(pos < v.size()){
ListExpr fl = getFaceList(v,pos);
if(first){
faces = nl->OneElemList(fl);
last = faces;
first = false;
} else {
last = nl->Append(last,fl);
}
}
return faces;
}
/*
~getCoord~
converts a double into aMPrecCoordinate
*/
MPrecCoordinate getCoord(double d, int scale, bool useStr, uint8_t digits){
if(!useStr){
MPrecCoordinate res(d,scale);
res *= scale;
return res;
}
MPrecCoordinate res(0);
res.readFromString(stringutils::double2str(d, digits),scale);
return res;
}
/*
~getPrecPoint~
Converts a point into a precise point
*/
MPrecPoint getPrecPoint( const Point& p, int scale, bool useStr,
uint8_t digits){
assert(scale>0);
MPrecCoordinate x = getCoord(p.GetX(),scale,useStr, digits);
MPrecCoordinate y = getCoord(p.GetY(), scale,useStr, digits);
MPrecPoint res(x,y);
return res;
}
/*
~getMPrecHsExact~
Converts a usual halfsegment into a precise one.
*/
MPrecHalfSegment getMPrecHsExact(const HalfSegment& hs, int scale){
assert(scale>0);
MPrecPoint lp( MPrecCoordinate(hs.GetLeftPoint().GetX(),scale),
MPrecCoordinate( hs.GetLeftPoint().GetY(), scale));
MPrecPoint rp( MPrecCoordinate(hs.GetRightPoint().GetX(),scale),
MPrecCoordinate( hs.GetRightPoint().GetY(), scale));
lp.compScale(scale);
rp.compScale(scale);
MPrecHalfSegment mhs(lp,rp,hs.IsLeftDomPoint(), hs.attr);
return mhs;
}
/*
~getMPrecHs~
Converts a usual halfsegment into a precise one using the given precision.
*/
bool getMPrecHs(const HalfSegment& hs,
int scale, uint32_t precision, MPrecHalfSegment& result){
assert(scale>0);
MPrecCoordinate x(0);
MPrecCoordinate y(0);
if(!x.readFromString(stringutils::double2str(hs.GetLeftPoint().GetX(),
precision),scale) ||
!y.readFromString(stringutils::double2str( hs.GetLeftPoint().GetY(),
precision), scale)){
assert(false);
}
MPrecPoint lp(x,y);
if(!x.readFromString(stringutils::double2str(hs.GetRightPoint().GetX(),
precision),scale) ||
!y.readFromString(stringutils::double2str( hs.GetRightPoint().GetY(),
precision), scale)){
assert(false);
}
MPrecPoint rp(x,y);
if(lp==rp) return false;
result.set(hs.IsLeftDomPoint(),lp,rp, FIRST, hs.attr);
return true;
}
bool readHalfSegment(ListExpr le, MPrecHalfSegment& result,
const bool includeScale, int scale){
if(includeScale){
if(!nl->HasLength(le,2)){
return false;
}
ListExpr sc = nl->First(le);
le = nl->Second(le);
if(nl->AtomType(sc)!=IntType){
return false;
}
scale = nl->IntValue(sc);
if(scale<=0){
return false;
}
}
if(!nl->HasLength(le,2)){
return false;
}
MPrecPoint p1(0,0);
MPrecPoint p2(0,0);
if( !readPoint(nl->First(le),p1,false,scale)
|| !readPoint(nl->Second(le),p2,false,scale)){
return false;
}
if(p1==p2){
return false;
}
AttrType dummy(0);
result = MPrecHalfSegment(p1,p2,true, dummy);
return true;
}
/*
3 Implementation of complex class methods
3.1 Precise Coordinate
*/
ListExpr PrecCoord::ToListExpr(ListExpr typeInfo) const{
if(!IsDefined()){
return listutils::getUndefined();
}
if(!coord.hasFracPart()){
return nl->TwoElemList(
nl->IntAtom(scale),
nl->OneElemList(
listutils::getInt64List(coord.getIntPart())));
}
MPrecCoordinate pc(coord,&fracStorage, scale);
return nl->TwoElemList(
nl->IntAtom(scale),
nl->TwoElemList(
listutils::getInt64List(pc.getIntPart()),
nl->TextAtom(pc.getFracAsText())));
}
bool PrecCoord::ReadFrom(ListExpr LE, const ListExpr typeInfo){
if(listutils::isSymbolUndefined(LE)){
SetDefined(false);
fracStorage.clean();
return true;
}
int64_t intPart=0;
if(!nl->HasLength(LE,2)){
return false;
}
ListExpr sl = nl->First(LE);
LE = nl->Second(LE);
int sc = nl->IntValue(sl);
if(sc<=0){
return false;
}
if(nl->HasLength(LE,1)){
if(!listutils::decodeInt64(nl->First(LE),intPart)){
return false;
}
coord = PPrecCoordinate(intPart,0);
fracStorage.clean();
scale = sc;
return true;
}
if(!nl->HasLength(LE,2)){
return false;
}
if(!listutils::decodeInt64(nl->First(LE),intPart)){
return false;
}
if(nl->AtomType(nl->Second(LE)) != TextType){
return false;
}
try{
MPrecCoordinate pc(intPart, nl->Text2String(nl->Second(LE)),1);
pc.appendFractional(&fracStorage);
coord = pc;
SetDefined(true);
scale = sc;
return true;
} catch(...){
return false;
}
}
/*
3.2 Precise Point
*/
bool PrecPoint::Intersects(const Rectangle<2>& rect,
const Geoid* geoid/*=0*/ ) const {
if(!IsDefined()){
return false;
}
CType p = GetValue();
double x = p.getX().toDouble();
double y = p.getY().toDouble();
double x1 = rect.MinD(0);
double x2 = rect.MaxD(0);
double y1 = rect.MinD(0);
double y2 = rect.MaxD(0);
return x>=x1 && x<=x2 && y>=y1 && y<=y2;
}
bool PrecPoint::ReadFrom(ListExpr LE, ListExpr typeInfo){
if(listutils::isSymbolUndefined(LE)){
SetDefined(false);
fracStorage.clean();
return true;
}
if(!nl->HasLength(LE,2)){
return false;
}
ListExpr sl = nl->First(LE);
LE = nl->Second(LE);
if(nl->AtomType(sl)!=IntType){
return false;
}
int32_t sc = nl->IntValue(sl);
if(sc <= 0){
return false;
}
scale = sc;
if(!nl->HasLength(LE,2)){
return false;
}
MPrecCoordinate x(0);
MPrecCoordinate y(0);
if(!::readFrom(nl->First(LE),x,false, scale)){
return false;
}
if(!::readFrom(nl->Second(LE),y,false, scale)){
return false;
}
fracStorage.clean();
x.appendFractional(&fracStorage);
y.appendFractional(&fracStorage);
pos.set(x,y);
SetDefined(true);
return true;
}
void PrecPoint::readFrom(const Point& p, int scale, bool useStr,
uint8_t digits ){
if(!p.IsDefined() || scale<=0){
SetDefined(false);
return;
}
MPrecPoint pp = getPrecPoint(p,scale,useStr, digits);
set(pp);
}
/*
3.3 PrecPoints
*/
ListExpr PrecPoints::ToListExpr (ListExpr typeInfo){
if(!IsDefined()){
return listutils::getUndefined();
}
if(gridPoints.Size()==0){
return nl->TheEmptyList();
}
ListExpr result = nl->OneElemList(
toListExpr(getPointAt(0))
);
ListExpr last = result;
for(size_t i=1;i<Size();i++){
last = nl->Append(last, toListExpr(getPointAt(i)));
}
return nl->TwoElemList( nl->IntAtom(scale), result);
}
int PrecPoints::compareTo(const PrecPoints& rhs)const{
if(!IsDefined()){
return rhs.IsDefined()?-1:0;
}
if(!rhs.IsDefined()){
return 1;
}
size_t ms = std::min(Size(), rhs.Size());
for(size_t i=0;i<ms;i++){
int cmp = getPointAt(i).compareTo(rhs.getPointAt(i));
if(cmp!=0) {
return cmp;
}
}
if(Size()>ms){
return 1;
}
if(rhs.Size()>ms){
return -1;
}
return 0;
}
std::ostream& PrecPoints::Print(std::ostream &os) const{
if(!IsDefined()){
os << "undef";
return os;
};
os << "(";
for(size_t i=0;i<Size();i++){
if(i>0) os << ", ";
os << getPointAt(i);
}
os << ")";
return os;
}
double PrecPoints::Distance(const Rectangle<2>& rect,
const Geoid* geoid/*=0*/) const {
assert(geoid==0);
if(!IsDefined()){
return -1;
}
if(Size()==0){
return -1;
}
double dist = getQDistance(rect,getPointAt(0));
for(size_t i=1;i<Size() && dist > 0;i++){
dist = std::min(dist, getQDistance(rect,getPointAt(i)));
}
return sqrt(dist);
}
bool PrecPoints::Intersects(const Rectangle<2>& rect,
const Geoid* geoid/*=0*/ ) const {
if(!IsDefined()){
return false;
}
if(!bbox.Intersects(rect)){
return false;
}
for(size_t i=0;i<Size();i++){
if(::intersects(rect, getPointAt(i))){
return true;
}
}
return false;
}
bool PrecPoints::ReadFrom(ListExpr LE, ListExpr typeInfo){
if(listutils::isSymbolUndefined(LE)){
SetDefined(false);
clear();
return true;
}
uint32_t sc=1;
if(!nl->HasLength(LE,2)){
return false;
}
ListExpr sl = nl->First(LE);
LE = nl->Second(LE);
if(nl->AtomType(sl)!=IntType){
return false;
}
int32_t a = nl->IntValue(sl);
if(a<=0){
return false;
}
sc = a;
if(nl->AtomType(LE)!=NoAtom){
return false;
}
clear();
startBulkLoad(sc);
while(!nl->IsEmpty(LE)){
ListExpr first = nl->First(LE);
LE = nl->Rest(LE);
MPrecPoint p(0,0);
if(!readPoint(first, p,false,sc)){
clear();
endBulkLoad(false);
return false;
}
append(p);
}
endBulkLoad(true);
SetDefined(true);
return true;
}
void PrecPoints::endBulkLoad(bool sort/*=true*/){
assert(bulkloadStorage);
if(sort){
MPrecPointComp cmp;
std::sort(bulkloadStorage->begin(), bulkloadStorage->end(), cmp);
}
// make vector persistent
bbox.SetDefined(false);
if(bulkloadStorage->size() == 0){
delete bulkloadStorage;
bulkloadStorage = 0;
return;
}
MPrecPoint lp(0,0);
for(size_t i=0;i<bulkloadStorage->size();i++){
MPrecPoint cp = bulkloadStorage->at(i);
if(i==0 || lp!=cp){
cp.appendFractional(&fracStorage);
PPrecPoint pcp = cp.getPersistent();
gridPoints.Append(pcp);
enlarge(bbox,cp);
lp = cp;
}
}
delete bulkloadStorage;
bulkloadStorage = 0;
SetDefined(true);
}
void PrecPoints::compScale(const MPrecCoordinate& s1,
const MPrecCoordinate& s2,
PrecPoints& result) const{
result.clear();
if(!IsDefined()){
result.SetDefined(false);
return;
}
result.startBulkLoad(scale);
for(size_t i=0;i<Size();i++){
MPrecPoint p = getPointAt(i);
p.compScale(s1,s2);
result.append(p);
}
result.endBulkLoad(false);
}
void PrecPoints::compTranslate(const MPrecCoordinate& t1,
const MPrecCoordinate& t2,
PrecPoints& result) const{
result.clear();
if(!IsDefined()){
result.SetDefined(false);
return;
}
result.startBulkLoad( scale);
for(size_t i=0;i<Size();i++){
MPrecPoint p = getPointAt(i);
p.compTranslate(t1,t2);
result.append(p);
}
result.endBulkLoad(false);
}
void PrecPoints::contains(const PrecPoints& ps, CcBool& result) const{
if(!IsDefined() || !ps.IsDefined()){
result.SetDefined(false);
return;
}
if(ps.Size()==0){ // the empty set is part of each set
result.Set(true,true);
return;
}
if(Size() < ps.Size()){
result.Set(true,false);
return;
}
size_t pos1=0; // position here
size_t pos2=0; // position in ps
while(pos1<Size() && pos2<ps.Size()){
MPrecPoint p1 = getPointAt(pos1);
MPrecPoint p2 = ps.getPointAt(pos2);
int cmp = p1.compareTo(p2);
if(cmp<0){
pos1++;
} else if (cmp==0){
pos1++;
pos2++;
} else {
result.Set(true,false);
return;
}
}
result.Set(true, pos2==ps.Size());
}
/*
~contains~
Checks whether p is contained in this set.
*/
void PrecPoints::contains(const PrecPoint& p, CcBool& result) const{
if(!IsDefined() || !p.IsDefined()){
result.SetDefined(false);
return;
}
if(Size()==0){
result.Set(true,false);
return;
}
MPrecPoint mp = p.GetValue();
size_t min = 0;
size_t max = Size();
while(min<max){
size_t mid = (min + max) / 2;
MPrecPoint tp = getPointAt(mid);
int cmp = mp.compareTo(tp);
if(cmp==0){
result.Set(true,true);
return;
}
if(cmp < 0){
max = mid - 1;
} else {
min = mid + 1;
}
}
if(min==max){
MPrecPoint tp = getPointAt(min);
int cmp = mp.compareTo(tp);
if(cmp==0){
result.Set(true,true);
return;
}
}
result.Set(true,false);
}
void PrecPoints::intersects(const PrecPoints& ps, CcBool& result)const{
if(!IsDefined() || !ps.IsDefined()){
result.SetDefined(false);
return;
}
if(Size()==0 || ps.Size()==0){
result.Set(true,false);
return;
}
size_t pos1 = 0;
size_t pos2 = 0;
while( pos1<Size() && pos2<ps.Size()){
MPrecPoint p1 = getPointAt(pos1);
MPrecPoint p2 = ps.getPointAt(pos2);
int cmp = p1.compareTo(p2);
if(cmp<0){
pos1++;
} else if(cmp>0){
pos2++;
} else {
result.Set(true,true);
return;
}
}
result.Set(true,false);
}
void PrecPoints::intersection(const PrecPoints& ps, PrecPoints& result) const{
result.clear();
if(!IsDefined() || !ps.IsDefined()){
result.SetDefined(false);
return;
}
result.startBulkLoad( scale);
size_t pos1 = 0;
size_t pos2 = 0;
while( pos1<Size() && pos2<ps.Size()){
MPrecPoint p1 = getPointAt(pos1);
MPrecPoint p2 = ps.getPointAt(pos2);
int cmp = p1.compareTo(p2);
if(cmp<0){
pos1++;
} else if(cmp>0){
pos2++;
} else {
result.append(p1);
pos1++;
pos2++;
}
}
result.endBulkLoad(false);
}
/*
~union~
compute the union of this and ps
*/
void PrecPoints::compUnion(const PrecPoints& ps, PrecPoints& result)const{
result.clear();
if(!IsDefined() || !ps.IsDefined()){
result.SetDefined(false);
return;
}
result.startBulkLoad(scale);
size_t pos1 = 0;
size_t pos2 = 0;
while( pos1<Size() && pos2<ps.Size()){
MPrecPoint p1 = getPointAt(pos1);
MPrecPoint p2 = ps.getPointAt(pos2);
int cmp = p1.compareTo(p2);
if(cmp<0){
result.append(p1);
pos1++;
} else if(cmp>0){
result.append(p2);
pos2++;
} else {
result.append(p1);
pos1++;
pos2++;
}
}
while(pos1<Size()){
MPrecPoint p1 = getPointAt(pos1);
result.append(p1);
pos1++;
}
while(pos2<ps.Size()){
MPrecPoint p2 = ps.getPointAt(pos2);
result.append(p2);
pos2++;
}
result.endBulkLoad(false);
}
/*
~difference~
compute the difference of this and ps
*/
void PrecPoints::difference(const PrecPoints& ps, PrecPoints& result)const{
result.clear();
if(!IsDefined() || !ps.IsDefined()){
result.SetDefined(false);
return;
}
result.startBulkLoad(scale);
size_t pos1 = 0;
size_t pos2 = 0;
while( pos1<Size() && pos2<ps.Size()){
MPrecPoint p1 = getPointAt(pos1);
MPrecPoint p2 = ps.getPointAt(pos2);
int cmp = p1.compareTo(p2);
if(cmp<0){
result.append(p1);
pos1++;
} else if(cmp>0){
pos2++;
} else {
pos1++;
pos2++;
}
}
while(pos1<Size()){
MPrecPoint p1 = getPointAt(pos1);
result.append(p1);
pos1++;
}
result.endBulkLoad(false);
}
/*
~readFrom~
Converts the argument into a precise value
*/
void PrecPoints::readFrom(const Points& points, int scale, bool useString,
uint8_t digits){
clear();
if(!points.IsDefined() || scale<=0){
SetDefined(false);
return;
}
SetDefined(true);
if(points.Size()==0){
return;
}
startBulkLoad(scale);
Point p;
MPrecPoint pp(0,0);
for(int i=0;i<points.Size();i++){
points.Get(i,p);
pp = getPrecPoint(p,scale,useString, digits);
append(pp);
}
endBulkLoad();
}
/*
3.3 precLine
*/
int PrecLine::compareTo(const PrecLine& rhs)const{
if(!IsDefined()){
return rhs.IsDefined()?-1:0;
}
if(!rhs.IsDefined()){
return 1;
}
int cbb = bbox.Compare(&rhs.bbox);
if(cbb!=0){
return cbb;
}
if(Size() < rhs.Size()){
return -1;
}
if(Size()> rhs.Size()){
return 1;
}
for(size_t i =0; i< Size(); i++){
MPrecHalfSegment hs1 = getHalfSegment(i);
MPrecHalfSegment hs2 = rhs.getHalfSegment(i);
int cmp = hs1.compareTo(hs2);
if(cmp!=0){
return cmp;
}
}
return 0;
}
ListExpr PrecLine::ToListExpr(ListExpr typeInfo) const{
if(!IsDefined()){
return listutils::getUndefined();
}
ListExpr hsList = nl->TheEmptyList();
ListExpr last;
bool first = true;
for(size_t i=0;i<Size();i++){
MPrecHalfSegment hs = getHalfSegment(i);
if(hs.isLeftDomPoint()){
if(first){
hsList = nl->OneElemList( toListExpr(hs));
last = hsList;
first = false;
} else {
last = nl->Append(last, toListExpr(hs));
}
}
}
return nl->TwoElemList( nl->IntAtom(scale),
hsList);
}
void PrecLine::readFrom(const Line& line, int scale, bool useString,
uint8_t digits){
if(!line.IsDefined() || scale<=0){
clear();
SetDefined(false);
return;
}
vector<MPrecHalfSegment> hsv1;
HalfSegment hs;
for(int i=0;i<line.Size();i++){
line.Get(i,hs);
if(useString){
MPrecHalfSegment tmp;
if(getMPrecHs(hs,scale,digits, tmp)){
hsv1.push_back(tmp);
}
} else {
hsv1.push_back(getMPrecHsExact(hs, scale));
}
}
vector<MPrecHalfSegment> hsv;
hstools::realminize(hsv1,hsv);
gridData.resize(hsv.size());
for(size_t i=0;i<hsv.size(); i++){
MPrecHalfSegment mhs = hsv[i];
mhs.appendTo(&gridData, &fracStorage);
enlarge(bbox, mhs.getLeftPoint());
enlarge(bbox, mhs.getRightPoint());
}
this->scale = scale;
SetDefined(true);
}
bool PrecLine::ReadFrom(ListExpr value, ListExpr typeInfo){
if(listutils::isSymbolUndefined(value)){
clear();
SetDefined(false);
return true;
}
if(!nl->HasLength(value,2)){
return false;
}
ListExpr sc = nl->First(value);
value = nl->Second(value);
if(nl->AtomType(sc)!=IntType ||
nl->AtomType(value)!=NoAtom){
return false;
}
int scale = nl->IntValue(sc);
if(scale<=0){
return false;
}
startBulkLoad();
AttrType dummy(0);
MPrecHalfSegment hs(MPrecPoint(0,0),MPrecPoint(1,0),true,dummy);
while(!nl->IsEmpty(value)){
ListExpr first = nl->First(value);
value = nl->Rest(value);
if(!readHalfSegment(first, hs,false,scale)){
clear();
SetDefined(false);
delete bulkloadStorage;
bulkloadStorage=0;
return false;
}
append(hs);
}
endBulkLoad();
this->scale = scale;
SetDefined(true);
return true;
}
void PrecLine::endBulkLoad(bool realminize){
assert(bulkloadStorage);
if(bulkloadStorage->empty()){
delete bulkloadStorage;
bulkloadStorage=0;
//scale = 1;
return;
}
hstools::sort(*bulkloadStorage);
vector<MPrecHalfSegment> v2;
if(realminize){
hstools::realminize(*bulkloadStorage,v2);
} else {
swap(v2, *bulkloadStorage);
}
for(size_t i=0;i<v2.size();i++){
v2[i].bringToMemory();
}
hstools::setPartnerNumbers(v2);
bbox.SetDefined(false);
scale = v2[0].getScale();
gridData.clean();
fracStorage.clean();
for(size_t i=0;i<v2.size();i++){
v2[i].appendTo(&gridData, &fracStorage);
enlarge(bbox, v2[i].getLeftPoint());
enlarge(bbox, v2[i].getRightPoint());
}
delete bulkloadStorage;
bulkloadStorage=0;
}
void PrecLine::intersects(const PrecLine& l2, CcBool& result) {
if(!IsDefined() || !l2.IsDefined()){
result.SetDefined(false);
return;
}
if(IsEmpty() || l2.IsEmpty()){
result.Set(true,false);
return;
}
if(!bbox.Intersects(l2.bbox)){
result.Set(true,false);
return;
}
mmrtree::RtreeT<2,size_t> tree1(4,8);
mmrtree::RtreeT<2,size_t> tree2(4,8);
vector<MPrecHalfSegment> v1;
vector<MPrecHalfSegment> v2;
size_t pos = 0;
size_t end = std::min(size(),l2.size());
while(pos<end){
MPrecHalfSegment hs1 = getHalfSegment(pos);
if(hs1.isLeftDomPoint()){
Rectangle<2> box = hs1.BoundingBox();
tree1.insert(box,v1.size());
v1.push_back(hs1);
mmrtree::RtreeT<2,size_t>::iterator * it = tree2.find(box);
size_t const* s;
while((s=it->next())!=0){
if( v2[*s].intersects(hs1)){
delete it;
result.Set(true,true);
return;
}
}
delete it;
}
MPrecHalfSegment hs2 = l2[pos];
if(hs2.isLeftDomPoint()){
Rectangle<2> box = hs2.BoundingBox();
tree2.insert(box,v2.size());
v2.push_back(hs2);
mmrtree::RtreeT<2,size_t>::iterator * it = tree1.find(box);
size_t const* s;
while((s=it->next())!=0){
if(v1[*s].intersects(hs2)){
delete it;
result.Set(true,true);
return;
}
}
delete it;
}
pos++;
}
// process remaining halfsegments of one of the lines
while(pos<size()){
MPrecHalfSegment hs1 = getHalfSegment(pos);
if(hs1.isLeftDomPoint()){
Rectangle<2> box = hs1.BoundingBox();
mmrtree::RtreeT<2,size_t>::iterator * it = tree2.find(box);
size_t const* s;
while((s=it->next())!=0){
if( v2[*s].intersects(hs1)){
delete it;
result.Set(true,true);
return;
}
}
delete it;
}
pos++;
}
while(pos<l2.size()){
MPrecHalfSegment hs2 = l2.getHalfSegment(pos);
if(hs2.isLeftDomPoint()){
Rectangle<2> box = hs2.BoundingBox();
mmrtree::RtreeT<2,size_t>::iterator * it = tree1.find(box);
size_t const* s;
while((s=it->next())!=0){
if( v1[*s].intersects(hs2)){
delete it;
result.Set(true,true);
return;
}
}
delete it;
}
pos++;
}
result.Set(true,false);
return;
}
void PrecLine::compUnion(const PrecLine& l2, PrecLine& result) const{
result.clear();
if(!IsDefined() || !l2.IsDefined()){
result.SetDefined(false);
return;
}
result.SetDefined(true);
result.startBulkLoad(getScale());
for(size_t i=0;i<Size();i++){
MPrecHalfSegment hs = getHalfSegment(i);
if(hs.isLeftDomPoint()){
result.append(hs);
}
}
for(size_t i=0;i<l2.Size();i++){
MPrecHalfSegment hs = l2.getHalfSegment(i);
if(hs.isLeftDomPoint()){
result.append(hs);
}
}
bool realmrequired = true;
if(Size()==0 || l2.Size()==0){
realmrequired = false;
} else {
realmrequired = bbox.Intersects(l2.bbox);
}
result.endBulkLoad(realmrequired);
}
void PrecLine::intersection(const PrecLine& l2, PrecLine& result) const{
result.clear();
if(!IsDefined() || !l2.IsDefined()){
result.SetDefined(false);
return;
}
if(!bbox.Intersects(l2.bbox)){ // intersection will be empty
return;
}
result.SetDefined(true);
vector<MPrecHalfSegment> rv;
vector<MPrecHalfSegment> v1;
for(size_t i=0;i<size();i++){
v1.push_back( (*this)[i]);
}
vector<MPrecHalfSegment> v2;
for(size_t i=0;i<l2.size();i++){
v1.push_back( l2[i]);
}
hstools::setOP(v1,v2,rv,hstools::INTERSECTION);
result.startBulkLoad();
for(size_t i=0;i< rv.size();i++){
if(rv[i].isLeftDomPoint()){
result.append(rv[i]);
}
}
result.endBulkLoad(false);
}
void PrecLine::difference(const PrecLine& l2, PrecLine& result) const{
result.clear();
if(!IsDefined() || !l2.IsDefined()){
result.SetDefined(false);
return;
}
if(!bbox.Intersects(l2.bbox)){ // intersection will be empty
return;
}
result.SetDefined(true);
vector<MPrecHalfSegment> v1;
vector<MPrecHalfSegment> v2;
for(size_t i=0;i<Size();i++){
MPrecHalfSegment hs = getHalfSegment(i);
v1.push_back(hs);
}
for(size_t i=0;i<l2.Size();i++){
MPrecHalfSegment hs = l2.getHalfSegment(i);
v2.push_back(hs);
}
vector<MPrecHalfSegment> rv;
hstools::setOP(v1,v2,rv,hstools::DIFFERENCE);
result.startBulkLoad();
for(size_t i=0;i< rv.size();i++){
if(rv[i].isLeftDomPoint()){
result.append(rv[i]);
}
}
result.endBulkLoad(false);
}
/*
3.4 precRegion
*/
int PrecRegion::compareTo(const PrecRegion& rhs)const{
if(!IsDefined()){
return rhs.IsDefined()?-1:0;
}
if(!rhs.IsDefined()){
return 1;
}
int cbb = bbox.Compare(&rhs.bbox);
if(cbb!=0){
return cbb;
}
if(Size() < rhs.Size()){
return -1;
}
if(Size()> rhs.Size()){
return 1;
}
for(size_t i =0; i< Size(); i++){
MPrecHalfSegment hs1 = getHalfSegment(i);
MPrecHalfSegment hs2 = rhs.getHalfSegment(i);
int cmp = hs1.compareTo(hs2);
if(cmp!=0){
return cmp;
}
}
return 0;
}
ListExpr PrecRegion::ToListExpr(ListExpr typeInfo) const{
if(!IsDefined()){
return listutils::getUndefined();
}
vector<MPrecHalfSegment> hsvec;
for(size_t i=0;i<Size();i++){
MPrecHalfSegment hs = getHalfSegment(i);
if(hs.isLeftDomPoint()){
hsvec.push_back(hs);
}
}
return nl->TwoElemList( nl->IntAtom(scale),
getRegionList(hsvec));
}
/*
~findExtension~
finds an unused segment having the same dominating point as the
segment at pos. If such an segment cannot be found, -1 is returned.
*/
int findExtension(vector<MPrecHalfSegment>& segments, int pos,
vector<bool>& used){
int ps = pos-1;
while(ps >= 0 && segments[ps].getDomPoint() == segments[pos].getDomPoint()){
if(!used[ps]){
return ps;
}
ps--;
}
ps = pos+1;
while(ps < (int)segments.size()
&& segments[ps].getDomPoint() == segments[pos].getDomPoint()){
if(!used[ps]){
return ps;
}
ps++;
}
return -1;
}
/*
~startCycle~
Starts to trace a cycle within the segments vector.
Each found subcycle is stored as a seperated face.
*/
void startCycle(vector<MPrecHalfSegment>& segments, vector<bool>& used,
int pos, int& faceno){
// TODO find sub cycles
int edgeno = 0;
MPrecPoint start = segments[pos].getLeftPoint();
MPrecPoint next = segments[pos].getRightPoint();
while((pos >=0) && (start != next)){
int partner = segments[pos].attributes.partnerno;
used[pos] = true;
used[partner] = true;
segments[pos].attributes.faceno = faceno;
segments[pos].attributes.cycleno = 0;
segments[pos].attributes.edgeno = edgeno;
segments[partner].attributes.faceno = faceno;
segments[partner].attributes.cycleno = 0;
segments[partner].attributes.edgeno = edgeno;
edgeno++;
pos = findExtension(segments,partner,used);
next = segments[partner].getRightPoint();
}
faceno++;
}
/*
~ computeRegion~
This function find cycles within the argument and sets
faceno, cycleno as well as edgeno for each cycle.
If the segments do not form a valid region (i.e. non closed
or overlapping cycles), an exception is thrown.
The partner numbers and the inside above flag must be
set correctly.
*/
void PrecRegion::computeRegion(vector<MPrecHalfSegment>& segments){
if(segments.empty()) return; // nothing to do
if( (segments.size() < 6)){ // too less halfsegments to form a region
throw 1; // TODO: use an exception class
}
if(segments.size() & 1u){ // odd number of halfsegments
throw 2;
}
// within a first step, we find all cycles.
// the basic idea is to follow a path having the interior of
// the region always at the same side, until the path is closed.
// we store all points having multiple possibilities for
// extending the path. Whenever a subpath is closed, this
// path will be stored seperately
vector<bool> used(segments.size(), false);
int pos = 0;
int faceno = 0;
while(pos < (int)segments.size()){
if(!used[pos]){
startCycle(segments, used, pos, faceno);
}
pos++;
}
// secondly, look, which cycle is contained in which other to
// assignde face number and cycle number
}
bool PrecRegion::endBulkLoad( bool sort,
bool setCoverageNo,
bool setPartnerNo,
bool computeRegion){
assert(bulkloadStorage);
// step 1 sort half segments
if(sort){
hstools::sort(*bulkloadStorage);
}
// do not accept unrealmed halfsegment sets
if(!hstools::checkRealm(*bulkloadStorage)){
delete bulkloadStorage;
bulkloadStorage=0;
return false;
}
// set the coverage number
if(setCoverageNo){
hstools::setCoverage(*bulkloadStorage);
}
// set partner numbers
if(setPartnerNo){
hstools::setPartnerNumbers(*bulkloadStorage);
}
// set faceno, cycleno and edgeno for each halfsegment
if(computeRegion){
try{
this->computeRegion(*bulkloadStorage);
} catch(...){ // halfsegments form not a set of cycles
delete bulkloadStorage;
bulkloadStorage = 0;
return false;
}
}
// copy the halfsegments from bulkloadstorage into
// persistent DB Array
for(size_t i=0;i<bulkloadStorage->size();i++){
(*bulkloadStorage)[i].appendTo(&gridData, &fracStorage);
enlarge(bbox, (*bulkloadStorage)[i].getLeftPoint());
enlarge(bbox, (*bulkloadStorage)[i].getRightPoint());
}
// remove bulkloadstorage
delete bulkloadStorage;
bulkloadStorage = 0;
return true;
}
void PrecRegion::cancelBulkLoad(){
assert(bulkloadStorage);
delete bulkloadStorage;
bulkloadStorage=0;
}
bool PrecRegion::addCycle(ListExpr cycle, int faceNo, int cycleNo, int& edgeNo){
if(nl->ListLength(cycle) < 3) {
return false;
}
vector<MPrecPoint> points;
MPrecPoint p(0,0);
while(!nl->IsEmpty(cycle)){
if(!readPoint(nl->First(cycle), p, false, scale)){
return false;
}
cycle = nl->Rest(cycle);
points.push_back(p);
}
// open cycle if closed
if(points[0]==points[points.size()-1]){
points.pop_back();
}
bool clockwise = precisetools::isClockwise(points);
bool isRight = cycleNo==0?clockwise:!clockwise;
// create halfsegments
for(size_t i = 0;i<points.size();i++){
MPrecPoint p1 = points[i];
MPrecPoint p2 = points[ (i+1) % points.size() ];
if(p1==p2){
return false;
}
AttrType a(0);
a.faceno = faceNo;
a.cycleno = cycleNo;
a.edgeno = edgeNo;
if(p1.getX()==p2.getX()){
a.insideAbove = p1.getY() < p2.getY()?!isRight:isRight;
} else {
a.insideAbove = p1.getX() < p2.getX()? !isRight:isRight;
}
MPrecHalfSegment hs1(p1,p2,true,a);
append(hs1);
edgeNo++;
}
return true;
}
bool PrecRegion::addFace(ListExpr face,
int faceNo, int& edgeNo ){
int cycleNo = 0;
if(nl->AtomType(face)!=NoAtom){
return false;
}
while(!nl->IsEmpty(face)){
if(!addCycle(nl->First(face), faceNo, cycleNo, edgeNo)){
return false;
}
face = nl->Rest(face);
}
return true;
}
bool PrecRegion::ReadFrom(ListExpr value, ListExpr type){
clear();
SetDefined(false);
if(listutils::isSymbolUndefined(value)){
return true;
}
if(!nl->HasLength(value,2)){
return false;
}
ListExpr scale = nl->First(value);
value = nl->Second(value);
if(nl->AtomType(scale)!=IntType){
return false;
}
int sc = nl->IntValue(scale);
if(sc < 1){
return false;
}
setScale(sc);
if(nl->AtomType(value)!=NoAtom){
return false;
}
SetDefined(true);
// liststructure is
// ( face_1, face_2 ,...)
// face_i = ( cycle_1, cycle_2 ,...)
// cycle_i = ( point_1, point_2 , ... )
startBulkLoad();
int faceNo = 0;
int edgeNo = 0;
while(!nl->IsEmpty(value)){
if(!addFace(nl->First(value),faceNo, edgeNo )) {
cancelBulkLoad();
SetDefined(false);
return false;
}
faceNo++;
value = nl->Rest(value);
}
return endBulkLoad();
}
bool correctHs(vector<MPrecHalfSegment>& v){
// check order
if(! hstools::isSorted(v)){
return false;
}
if(!hstools::checkRealm(v)){
return false;
}
return true;
// todo : implement this function
// 1. if not ordered : reorder and recompute partnernumbers
// 2. Check whether cycles are connected
}
void PrecRegion::readFrom(const Region& reg, int scale, bool useString,
uint8_t digits){
if(!reg.IsDefined() || scale<=0){
clear();
SetDefined(false);
return;
}
vector<MPrecHalfSegment> hsv;
HalfSegment hs;
for(int i=0;i<reg.Size();i++){
reg.Get(i,hs);
if(useString){
MPrecHalfSegment tmp;
if(getMPrecHs(hs, scale, digits,tmp)){
hsv.push_back(tmp);
}
} else {
hsv.push_back(getMPrecHsExact(hs, scale));
}
}
clear();
if(!correctHs(hsv)){
SetDefined(false);
return;
}
gridData.resize(hsv.size());
for(size_t i=0;i<hsv.size(); i++){
MPrecHalfSegment mhs = hsv[i];
mhs.appendTo(&gridData, &fracStorage);
enlarge(bbox, mhs.getLeftPoint());
enlarge(bbox, mhs.getRightPoint());
}
this->scale = scale;
SetDefined(true);
}
void PrecRegion::setOp(const PrecRegion& r, PrecRegion & result,
hstools::SETOP op) const{
result.clear();
// 1. Special cases
// 1.1 Undefined values
if(!IsDefined() || !r.IsDefined()){
result.SetDefined(false);
return;
}
// 1.2 r is empty
if(r.size()==0){
switch(op){
case hstools::UNION: result = *this; return;
case hstools::INTERSECTION: return;
case hstools::DIFFERENCE: result = *this; return;
default : assert(false);
}
}
// 1.3 this is empty
if(size()==0){
switch(op){
case hstools::UNION: result = r; return;
case hstools::INTERSECTION: return;
case hstools::DIFFERENCE: return;
default: assert(false);
}
}
// 1.4. disjoint bounding boxes
if(!BoundingBox().Intersects(r.BoundingBox())){
switch(op){
case hstools::UNION :{
result.startBulkLoad();
for(unsigned int i=0;i<size();i++){
MPrecHalfSegment h = getHalfSegment(i);
if(h.isLeftDomPoint()){
result.append(h);
}
}
for(size_t i=0;i<r.size();i++){
MPrecHalfSegment h = r.getHalfSegment(i);
if(h.isLeftDomPoint()){
result.append(h);
}
}
result.endBulkLoad(false);
}
case hstools::INTERSECTION: return;
case hstools::DIFFERENCE: result = *this; return;
default: assert(false);
}
}
// 2. normal case
// sweep status structure
avltree::AVLTree<MPrecHalfSegment,
hstools::YComparator<MPrecHalfSegment> > sss;
// event structure
hstools::EventStructure<PrecRegion,PrecRegion> es(this,&r);
AttrType dummy;
MPrecHalfSegment current (MPrecPoint(0,0), MPrecPoint(1,1), true, dummy);
int source;
MPrecHalfSegment * left;
MPrecHalfSegment * right;
MPrecHalfSegment * stored;
vector<MPrecHalfSegment> realmRes;
//int edgeno = 0;
result.startBulkLoad();
while((source = es.next(current))){
if(current.isLeftDomPoint()){ // left end point
// check for overlapping segments
if((stored = sss.getMember(current,left,right))){
// overlapping segment found
assert(stored->getOwner()!=BOTH);
assert(current.getOwner()!=stored->getOwner());
assert(current.getOwner()!=BOTH);
hstools::makeRealm(*stored,current,realmRes);
sss.remove(*stored);
sss.insert(realmRes[0]);
assert(realmRes[0].getOwner()==BOTH);
assert(realmRes[0].attributes.coverageno <3);
realmRes[0].setLDP(false);
es.push(realmRes[0]);
for(size_t i=1;i<realmRes.size();i++){
es.push(realmRes[i]);
realmRes[i].setLDP(false);
es.push(realmRes[i]);
}
} else {
// no overlapping element exists
// set coverage number for current
if(current.getOwner()!=BOTH){
if(left){
current.attributes.coverageno = left->attributes.coverageno;
if(current.attributes.insideAbove){
current.attributes.coverageno++;
} else {
current.attributes.coverageno--;
}
} else {
assert(current.attributes.insideAbove);
current.attributes.coverageno = 1;
}
}
assert(current.attributes.coverageno>=0);
assert(current.attributes.coverageno<3);
sss.insertN(current,left,right);
if(left && !left->checkRealm(current)){
hstools::makeRealm(*left,current,realmRes);
sss.remove(*left);
sss.remove(current);
sss.insert(realmRes[0]);
sss.insert(realmRes[1]);
current = realmRes[1];
realmRes[0].setLDP(false);
realmRes[1].setLDP(false);
es.push(realmRes[0]);
es.push(realmRes[1]);
for(size_t i=2;i<realmRes.size();i++){
es.push(realmRes[i]);
realmRes[i].setLDP(false);
es.push(realmRes[i]);
}
}
if( right && !right->checkRealm(current)){
hstools::makeRealm(*right, current,realmRes);
assert(sss.remove(*right));
assert(sss.remove(current));
sss.insert(realmRes[0]);
sss.insert(realmRes[1]);
current = realmRes[1];
realmRes[0].setLDP(false);
realmRes[1].setLDP(false);
es.push(realmRes[0]);
es.push(realmRes[1]);
for(size_t i=2;i<realmRes.size();i++){
es.push(realmRes[i]);
realmRes[i].setLDP(false);
es.push(realmRes[i]);
}
}
}
} else { // right end point
if((stored = sss.getMember(current))){
if(stored->sameGeometry(current)){
current = *stored;
sss.removeN(current,left,right);
if(left && right && !left->checkRealm(*right)){
// cout << "realm neighbors" << endl;
hstools::makeRealm(*left, *right, realmRes);
sss.remove(*left);
sss.remove(*right);
sss.insert(realmRes[0]);
sss.insert(realmRes[1]);
realmRes[0].setLDP(false);
realmRes[1].setLDP(false);
es.push(realmRes[0]);
es.push(realmRes[1]);
for(size_t i=2;i<realmRes.size();i++){
es.push(realmRes[i]);
realmRes[i].setLDP(false);
es.push(realmRes[i]);
}
}
switch(op){
case hstools::UNION :
if(current.getOwner()==BOTH){
if(current.attributes.coverageno!=1){
result.append(current);
}
} else {
if(current.attributes.insideAbove){
if(current.attributes.coverageno!=2){
result.append(current);
}
} else {
if(current.attributes.coverageno==0){
result.append(current);
}
}
}
break;
case hstools::DIFFERENCE :
switch(current.getOwner()){
case FIRST :
if(current.attributes.insideAbove){
if(current.attributes.coverageno==1){
result.append(current);
}
} else {
if(current.attributes.coverageno==0){
result.append(current);
}
}
break;
case SECOND :
if(current.attributes.insideAbove){
if(current.attributes.coverageno==2){
current.attributes.insideAbove = false;
result.append(current);
}
} else {
if(current.attributes.coverageno==1){
current.attributes.insideAbove = true;
result.append(current);
}
}
break;
case BOTH :
if(current.attributes.coverageno==1){
result.append(current);
}
break;
default : assert(false);
}
break;
case hstools::INTERSECTION :
switch(current.getOwner()){
case FIRST:
case SECOND:
if(current.attributes.insideAbove){
if(current.attributes.coverageno==2){
result.append(current);
}
} else {
if(current.attributes.coverageno==1){
result.append(current);
}
}
break;
case BOTH:
if(current.attributes.coverageno==2){
current.attributes.insideAbove = true;
result.append(current);
} else if(current.attributes.coverageno==0){
current.attributes.insideAbove = false;
result.append(current);
}
break;
default: assert(false);
}
}
}
}
}
}
result.SetDefined(true);
result.endBulkLoad();
}