/* ---- 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(xy2){ return ( (x1-x)*(x1-x) + (y2-y)*(y2-y)); } return (x1-x) * (x1-x); } if(x>x2){ if(yy2){ return ( (x2-x)*(x2-x) + (y2-y)*(y2-y)); } return (x-x2)*(x-x2); } if(yy2){ 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(xx2 || y > y2){ return false; } return true; } ListExpr getCycleList(const vector& 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_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){ 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;iAppend(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;ims){ 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;i0) 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 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;iHasLength(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;isize();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;i0){ 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( pos10){ 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( pos10){ result.append(p2); pos2++; } else { result.append(p1); pos1++; pos2++; } } while(pos10){ pos2++; } else { pos1++; pos2++; } } while(pos1 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;iOneElemList( 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 hsv1; HalfSegment hs; for(int i=0;i hsv; hstools::realminize(hsv1,hsv); gridData.resize(hsv.size()); for(size_t i=0;iscale = 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 v2; if(realminize){ hstools::realminize(*bulkloadStorage,v2); } else { swap(v2, *bulkloadStorage); } for(size_t i=0;i tree1(4,8); mmrtree::RtreeT<2,size_t> tree2(4,8); vector v1; vector v2; size_t pos = 0; size_t end = std::min(size(),l2.size()); while(pos 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 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 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 rv; vector v1; for(size_t i=0;i v2; for(size_t i=0;i v1; vector v2; for(size_t i=0;i 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 hsvec; for(size_t i=0;iTwoElemList( 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& segments, int pos, vector& 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& segments, vector& 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& 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 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;isize();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 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;iAtomType(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& 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 hsv; HalfSegment hs; for(int i=0;iscale = 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 > sss; // event structure hstools::EventStructure es(this,&r); AttrType dummy; MPrecHalfSegment current (MPrecPoint(0,0), MPrecPoint(1,1), true, dummy); int source; MPrecHalfSegment * left; MPrecHalfSegment * right; MPrecHalfSegment * stored; vector 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;iattributes.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;icheckRealm(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;isameGeometry(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