/* ---- This file is part of SECONDO. Copyright (C) 2017, 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 ---- //[_] [\_] */ #include "RegionT.h" #include "SimpleLineT.h" #include "RegionCreator.h" #include #include #include "RobustSetOps.h" #include "WinUnix.h" /* 11.4 Implementation of Class ~Region~ 11.4.1 Constructors */ templateclass Array> inline RegionT::RegionT( const int initsize ) : StandardSpatialAttribute<2>(true), region( initsize ), bbox( false ), noComponents( 0 ), ordered( true ) { } bool IsInsideAbove(const HalfSegment& hs, const Point& thirdPoint); templateclass Array> RegionT::RegionT( const Point& p1, const Point& p2, const Point& p3 ): StandardSpatialAttribute<2>(true),region(6) { Clear(); if( !p1.IsDefined() || !p2.IsDefined() || !p3.IsDefined() ){ SetDefined(false); // UNDEFINED region } else if(AlmostEqual(p1,p2) || AlmostEqual(p2,p3) || AlmostEqual(p3,p1) ){ SetDefined(true); // EMPTY region } else { // triangular region SetDefined(true); StartBulkLoad(); HalfSegment hs; int edgecnt = 0; hs.Set(true,p1,p2); hs.attr.faceno = 0; // only one face hs.attr.cycleno = 0; // only one cycle hs.attr.edgeno = edgecnt; hs.attr.partnerno = edgecnt++; hs.attr.insideAbove = IsInsideAbove(hs,p3); *this += hs; hs.SetLeftDomPoint( !hs.IsLeftDomPoint() ); *this += hs; hs.Set(true,p2,p3); hs.attr.faceno = 0; // only one face hs.attr.cycleno = 0; // only one cycle hs.attr.edgeno = edgecnt; hs.attr.partnerno = edgecnt++; hs.attr.insideAbove = IsInsideAbove(hs,p1); *this += hs; hs.SetLeftDomPoint( !hs.IsLeftDomPoint() ); *this += hs; hs.Set(true,p3,p1); hs.attr.faceno = 0; // only one face hs.attr.cycleno = 0; // only one cycle hs.attr.edgeno = edgecnt; hs.attr.partnerno = edgecnt++; hs.attr.insideAbove = IsInsideAbove(hs,p2); *this += hs; hs.SetLeftDomPoint( !hs.IsLeftDomPoint() ); *this += hs; EndBulkLoad(); } } templateclass Array> template class Array2> RegionT::RegionT( const RegionT& cr, bool onlyLeft ) : StandardSpatialAttribute<2>(cr.IsDefined()), region( cr.Size() ), bbox( cr.bbox ), noComponents( cr.NoComponents() ), ordered( true ) { if( IsDefined() && cr.Size() >0 ) { assert( cr.IsOrdered() ); if( !onlyLeft ){ convertDbArrays(cr.region,region); } else { StartBulkLoad(); HalfSegment hs; int j=0; for( int i = 0; i < cr.Size(); i++ ) { cr.Get( i, hs ); if (hs.IsLeftDomPoint()) { region.Put( j, hs ); j++; } } EndBulkLoad( false, false, false, false ); } } } templateclass Array> RegionT::RegionT( const RegionT& cr) : StandardSpatialAttribute<2>(cr.IsDefined()), region( cr.Size() ), bbox( cr.bbox ), ordered( true ) { if(IsDefined()) { // NoComponents() can only be called on defined regions noComponents = cr.NoComponents(); if(cr.Size() > 0) { assert( cr.IsOrdered() ); region.copyFrom(cr.region); } } } templateclass Array> template class Array2> RegionT::RegionT( const RegionT& cr) : StandardSpatialAttribute<2>(cr.IsDefined()), region( cr.Size() ), bbox( cr.bbox ), noComponents( cr.NoComponents() ), ordered( true ) { if( IsDefined() && cr.Size() >0 ) { assert( cr.IsOrdered() ); convertDbArrays(cr.region,region); } } templateclass Array> RegionT::RegionT( const Rectangle<2>& r ) :StandardSpatialAttribute<2>(r.IsDefined()), region(8) { Clear(); if( r.IsDefined() ) { SetDefined( true); HalfSegment hs; int partnerno = 0; double min0 = r.MinD(0), max0 = r.MaxD(0), min1 = r.MinD(1), max1 = r.MaxD(1); Point v1(true, max0, min1), v2(true, max0, max1), v3(true, min0, max1), v4(true, min0, min1); if( AlmostEqual(v1, v2) || AlmostEqual(v2, v3) || AlmostEqual(v3, v4) || AlmostEqual(v4, v1) ) { // one interval is (almost) empty, so will be the region SetDefined( true ); return; } SetDefined( true ); StartBulkLoad(); hs.Set(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.Set(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.Set(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.Set(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 ); } } /* Destroy This will destroy the contained flob. */ templateclass Array> inline void RegionT::Destroy() { region.destroy(); } /* ~Bounding Box~ If the geoid is null, this function just returns the internally stored box. Otherwise, a box is computed according the given geoid. */ templateclass Array> inline const Rectangle<2> RegionT::BoundingBox( const Geoid* geoid /*=0*/) const { if(geoid){ // spherical geometry case: if(!geoid->IsDefined() || !IsDefined()){ return Rectangle<2>(false); } Rectangle<2> geobbox = Rectangle<2>(false); for (int i=0; iclass Array> inline bool RegionT::IsOrdered() const { return ordered; } /* ~GetAttr~ Returns the attributes of the halfsegment stored at the specified position. */ templateclass Array> inline const AttrType& RegionT::GetAttr( int position ) const { assert(( position>=0) && (position<=Size()-1)); HalfSegment hs; region.Get( position, &hs); return hs.GetAttr(); } /* ~UpdateAttr~ Changes the attributes of the halfsegment at the current position of the 'iterator'. */ templateclass Array> inline void RegionT::UpdateAttr( AttrType& attr ) { if (( pos>=0) && (pos<=Size()-1)) { HalfSegment hs; region.Get( pos, &hs); hs.SetAttr( attr ); region.Put( pos, hs ); } } /* ~UpdateAttr~ Changes the attributes of the halfssegment at the speicfied position, */ templateclass Array> inline void RegionT::UpdateAttr( int position, AttrType& attr ) { if (( position>=0) && (position<=Size()-1)) { HalfSegment hs; region.Get( position, &hs ); hs.SetAttr( attr ); region.Put( position, hs ); } } /* Resets the internally 'iterator'. */ templateclass Array> inline void RegionT::SelectFirst() const { if( IsEmpty() ) pos = -1; else pos = 0; } /* moves the internally iterator forward. */ templateclass Array> inline void RegionT::SelectNext() const { if( pos >= 0 && pos < Size() - 1 ) pos++; else pos = -1; } /* Checks whether the internally iterator is at the end. */ templateclass Array> inline bool RegionT::EndOfHs() const { return (pos==-1); } /* Returns the halfsegment at the current iterator position. */ templateclass Array> inline bool RegionT::GetHs(HalfSegment& hs ) const { assert( IsDefined() ); if( pos >= 0 && pos <= Size()-1 ) { region.Get( pos, &hs ); return true; } return false; } /* resizes the halfsegment array. */ templateclass Array> inline void RegionT::Resize(const int newSize){ if(newSize>Size()){ region.resize(newSize); } } /* Resizes the halfsegment array to fit exactly the contained halfsegments. */ templateclass Array> inline void RegionT::TrimToSize(){ region.TrimToSize(); } /* switches to bulkload mode */ templateclass Array> void RegionT::StartBulkLoad() { ordered = false; } /* Finishes the bulkload mode. Be carefully with the flags. */ templateclass Array> void RegionT::EndBulkLoad( bool sort, bool setCoverageNo, bool setPartnerNo, bool computeRegion ) { if( !IsDefined() ) { Clear(); return; } if( sort ) { Sort(); } if( setCoverageNo ) { HalfSegment hs; int currCoverageNo = 0; for( int i = 0; i < this->Size(); i++ ) { Get( i, hs ); if( hs.IsLeftDomPoint() ) currCoverageNo++; else currCoverageNo--; hs.attr.coverageno = currCoverageNo; region.Put( i, hs ); } } if( setPartnerNo ) SetPartnerNo(); if( computeRegion ) { try{ ComputeRegion(); } catch(...){ RegionCreator::createRegion(®ion,this); } } region.TrimToSize(); ordered = true; } /* Checks whether the region contains p. Returns also true if the p is located of the region's boundary. */ templateclass Array> bool RegionT::Contains( const Point& p, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( p.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if( IsEmpty() || !p.IsDefined() || (geoid && !geoid->IsDefined())){ return false; } if( !p.Inside(bbox) ){ return false; } assert( IsOrdered() ); std::map faceISN; HalfSegment hs; int coverno=0; int startpos=0; double y0; //1. find the right place by binary search if( Find( p, startpos ) ){ return true; } if ( startpos == 0 ){ //p is smallest return false; } else if ( startpos == Size() ){ //p is largest return false; } int i = startpos - 1; //2. deal with equal-x hs's region.Get( i, hs ); while( i > 0 && hs.GetDomPoint().GetX() == p.GetX() ){ if( hs.Contains(p,geoid) ){ 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; } } region.Get( --i, hs ); } // 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 ){ this->Get(i, hs); if( hs.Contains(p) ){ return true; } if( hs.IsLeftDomPoint() && hs.GetLeftPoint().GetX() <= p.GetX() && p.GetX() <= hs.GetRightPoint().GetX() ){ 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( std::map::iterator iter = faceISN.begin(); iter != faceISN.end(); iter++ ){ if( iter->second % 2 != 0 ){ return true; } } return false; } /* Checks whether p is located in the interior of this region. */ templateclass Array> bool RegionT::InnerContains( const Point& p, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( p.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if( IsEmpty() || !p.IsDefined() || (geoid && !geoid->IsDefined())){ return false; } if( !p.Inside(bbox) ){ return false; } assert( IsOrdered() ); std::map faceISN; HalfSegment hs; int coverno = 0, startpos = 0; double y0; //1. find the right place by binary search if( Find( p, startpos ) ){ return false; } if ( startpos == 0 ){ //p is smallest return false; } else if ( startpos == Size() ){ //p is largest return false; } int i = startpos - 1; //2. deal with equal-x hs's region.Get( i, hs ); while( i > 0 && hs.GetDomPoint().GetX() == p.GetX() ){ if( hs.Contains(p,geoid) ){ 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; } } region.Get( --i, hs ); } // 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 ){ this->Get(i, hs); if( hs.Contains(p) ){ return false; } if( hs.IsLeftDomPoint() && hs.GetLeftPoint().GetX() <= p.GetX() && p.GetX() <= hs.GetRightPoint().GetX() ){ 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( std::map::iterator iter = faceISN.begin(); iter != faceISN.end(); iter++ ){ if( iter->second % 2 != 0 ){ return true; } } return false; } /* Checks whether this regions intersects inHs. */ templateclass Array> bool RegionT::Intersects( const HalfSegment& inHs, const Geoid* geoid/*=0*/) const { assert( IsDefined() ); assert( !geoid || geoid->IsDefined() ); if( !IsEmpty() && bbox.Intersects( inHs.BoundingBox() ) ) { if( Contains( inHs.GetLeftPoint(), geoid ) || Contains( inHs.GetRightPoint(), geoid ) ){ return true; } HalfSegment hs; for( int i = 0; i < Size(); i++ ){ Get( i, hs ); if( hs.Intersects( inHs, geoid ) ){ return true; } } } return false; } /* CHecks whether this region contains hs. */ templateclass Array> bool RegionT::Contains( const HalfSegment& hs, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ std::cerr << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented!." << std::endl; assert(false); // TODO: implement sperical geometry case } if( IsEmpty() ){ return false; } if( !hs.GetLeftPoint().Inside(bbox,geoid) || !hs.GetRightPoint().Inside(bbox,geoid) ){ return false; } if( !Contains(hs.GetLeftPoint(),geoid) || !Contains(hs.GetRightPoint(),geoid) ){ return false; } HalfSegment auxhs; bool checkMidPoint = false; std::vector intersection_points; //now we know that both endpoints of hs is inside region for( int i = 0; i < Size(); i++ ){ Get(i, auxhs); if( auxhs.IsLeftDomPoint() ){ if( hs.Crosses(auxhs,geoid) ){ return false; } else if( hs.Inside(auxhs,geoid) ){//hs is part of the border return true; } else if( hs.Intersects(auxhs,geoid)){ if(auxhs.Contains(hs.GetLeftPoint(),geoid) || auxhs.Contains(hs.GetRightPoint(),geoid) || hs.Contains(auxhs.GetLeftPoint(),geoid) || hs.Contains(auxhs.GetRightPoint(),geoid)){ checkMidPoint = true; //the intersection point that is not the endpoint Point temp_p; if(hs.Intersection(auxhs,temp_p, geoid)) intersection_points.push_back(temp_p); HalfSegment temp_hs; if(hs.Intersection(auxhs, temp_hs, geoid)){ intersection_points.push_back(temp_hs.GetLeftPoint()); intersection_points.push_back(temp_hs.GetRightPoint()); } } } } } if( checkMidPoint ){ Point midp( true, ( hs.GetLeftPoint().GetX() + hs.GetRightPoint().GetX() ) / 2, ( hs.GetLeftPoint().GetY() + hs.GetRightPoint().GetY() ) / 2 ); if( !Contains( midp ) ){ return false; } } for(unsigned int i = 0;i < intersection_points.size();i++){ //cout<class Array> bool RegionT::InnerContains( const HalfSegment& hs, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( !geoid || geoid->IsDefined() ); if( IsEmpty() ){ return false; } if( !hs.GetLeftPoint().Inside(bbox,geoid) || !hs.GetRightPoint().Inside(bbox,geoid) ){ return false; } if( !InnerContains(hs.GetLeftPoint(),geoid) || !InnerContains(hs.GetRightPoint(),geoid) ){ return false; } HalfSegment auxhs; //now we know that both endpoints of hs are completely inside the region for( int i = 0; i < Size(); i++ ){ Get(i, auxhs); if( auxhs.IsLeftDomPoint() ){ if( hs.Intersects( auxhs, geoid ) ){ return false; } } } return true; } templateclass Array> bool RegionT::HoleEdgeContain( const HalfSegment& hs, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( !geoid || geoid->IsDefined() ); if( !IsEmpty() ) { return false; } HalfSegment auxhs; for( int i = 0; i < Size(); i++ ){ Get( i, auxhs ); if( auxhs.IsLeftDomPoint() && auxhs.attr.cycleno > 0 && hs.Inside( auxhs, geoid ) ){ return true; } } return false; } /* 4.4.7 Operation ~intersects~ */ templateclass Array> template class ArrayT2> bool RegionT::Intersects( const RegionT &r, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if( IsEmpty() || r.IsEmpty() || (geoid && !geoid->IsDefined()) ){ return false; } if( !BoundingBox().Intersects( r.BoundingBox(), geoid ) ){ return false; } assert( IsOrdered() ); assert( r.IsOrdered() ); if( Inside( r, geoid ) || r.Inside( *this, geoid ) ){ return true; } HalfSegment 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, geoid ) ){ return true; } } } } return false; } /* Intersection with different data types */ templateclass Array> templateclass Array2> void RegionT::Intersection(const Point& p, PointsT& result, const Geoid* geoid/*=0*/) const{ result.Clear(); if(!IsDefined() || !p.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.SetDefined(false); return; } result.SetDefined(true); if(this->Contains(p,geoid)){ result+= p; } } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Intersection(const PointsT& ps, PointsT& result, const Geoid* geoid/*=0*/) const{ result.Clear(); if(!IsDefined() || !ps.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.SetDefined(false); return; } Point p(true); result.StartBulkLoad(); for(int i=0;iContains(p,geoid)){ result += p; } } result.EndBulkLoad(false,false,false); } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Intersection(const LineT& l, LineT& result, const Geoid* geoid/*=0*/) const{ try{ SetOp(l,*this,result,avlseg::intersection_op, geoid, true); } catch (...){ // compute intersection using robust implementation std::cerr << "Problem during plane sweep detected, " << "switch to slow implementation" << std::endl; robust::intersection(*this,l,result); } } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Intersection(const RegionT& r, RegionT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,r,result,avlseg::intersection_op, geoid); } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Intersection(const SimpleLineT& l, SimpleLineT& result, const Geoid* geoid/*=0*/) const{ SetOp(l,*this,result,avlseg::intersection_op, geoid); } templateclass Array> templateclass Array2> void RegionT::Union(const Point& p, RegionT& result, const Geoid* geoid/*=0*/) const{ if(!IsDefined() || !p.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.Clear(); result.SetDefined(false); return; } result.SetDefined(true); result.CopyFrom(this); } /* Union with different spatial types. */ templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Union(const PointsT& ps, RegionT& result, const Geoid* geoid/*=0*/) const{ if(!IsDefined() || !ps.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.Clear(); result.SetDefined(false); return; } result.SetDefined(true); result.CopyFrom(this); } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Union(const LineT& line, RegionT& result, const Geoid* geoid/*=0*/) const{ if(!IsDefined() || !line.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.Clear(); result.SetDefined(false); return; } result.SetDefined(true); result.CopyFrom(this); } templateclass Array> template class ArrayT2, template class ArrayT3> void RegionT::Union(const RegionT& region, RegionT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,region,result,avlseg::union_op, geoid); } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Union(const SimpleLineT& line, RegionT& result, const Geoid* geoid/*=0*/) const{ if(!IsDefined() || !line.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.Clear(); result.SetDefined(false); return; } result.SetDefined(true); result.CopyFrom(this); } templateclass Array> templateclass Array2> void RegionT::Minus(const Point& p, RegionT& result, const Geoid* geoid/*=0*/) const{ if(!IsDefined() || !p.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.Clear(); result.SetDefined(false); return; } result.SetDefined(true); result.CopyFrom(this); } /* Implementation of Minus. */ templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Minus(const PointsT& ps, RegionT& result, const Geoid* geoid/*=0*/) const{ if(!IsDefined() || !ps.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.Clear(); result.SetDefined(false); return; } result.SetDefined(true); result.CopyFrom(this); } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Minus(const LineT& line, RegionT& result, const Geoid* geoid/*=0*/) const{ if(!IsDefined() || !line.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.Clear(); result.SetDefined(false); return; } result.SetDefined(true); result.CopyFrom(this); } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Minus(const RegionT& region, RegionT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,region,result,avlseg::difference_op, geoid); } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::Minus(const SimpleLineT & line, RegionT& result, const Geoid* geoid/*=0*/) const{ if(!IsDefined() || !line.IsDefined() || (geoid && !geoid->IsDefined()) ){ result.Clear(); result.SetDefined(false); return; } result.SetDefined(true); result.CopyFrom(this); } /* Inside check. */ templateclass Array> template class Array2> bool RegionT::Inside( const RegionT& r, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(!IsDefined() || !r.IsDefined() || (geoid && !geoid->IsDefined()) ){ return false; } if( IsEmpty() ){ return true; } if(r.IsEmpty()){ return false; } assert( IsOrdered() ); assert( r.IsOrdered() ); if( !r.BoundingBox().Contains( bbox, geoid ) ){ return false; } HalfSegment hs1, hs2; for( int i = 0; i < Size(); i++ ){ Get( i, hs1 ); if( hs1.IsLeftDomPoint() ){ if( !r.Contains( hs1,geoid ) ){ 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,geoid ) ){ existhole=true; if( !Contains( hs2,geoid ) ){ allholeedgeinside=false; } } } } if( existhole && allholeedgeinside ){ return false; } return true; } /* Check for adjacency with another region. */ templateclass Array> templateclass Array2> bool RegionT::Adjacent( const RegionT& r, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if( IsEmpty() || r.IsEmpty() || (geoid && !geoid->IsDefined()) ){ return false; } if( !BoundingBox().Intersects( r.BoundingBox(),geoid ) ){ return false; } assert( IsOrdered() ); assert( r.IsOrdered() ); if( Inside( r,geoid ) || r.Inside( *this,geoid ) ) return false; HalfSegment 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,geoid ) ){ if( hs1.Crosses( hs2, geoid ) ){ return false; } found = true; } } } } return found; } /* Check for overlap. */ templateclass Array> templateclass Array2> bool RegionT::Overlaps( const RegionT& r, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if( IsEmpty() || r.IsEmpty() || (geoid && !geoid->IsDefined()) ){ return false; } if( !BoundingBox().Intersects( r.BoundingBox(),geoid ) ){ return false; } assert( IsOrdered() ); assert( r.IsOrdered() ); if( Inside( r ) || r.Inside( *this ) ) return true; HalfSegment 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,geoid ) ){ return true; } } } } } return false; } /* Checks whether p is on border of this region. */ templateclass Array> bool RegionT::OnBorder( const Point& p, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( p.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(IsEmpty() || !p.IsDefined() || (geoid && !geoid->IsDefined()) ){ return false; } int pos; if( Find( p, pos ) ){ // the point is found on one half segment return true; } if( pos == 0 || pos == Size() ){ // the point is smaller or bigger than all segments return false; } HalfSegment hs; pos--; while( pos >= 0 ){ Get( pos--, hs ); if( hs.IsLeftDomPoint() && hs.Contains( p,geoid ) ){ return true; } } return false; } templateclass Array> bool RegionT::InInterior( const Point& p, const Geoid* geoid/*=0*/ ) const { return InnerContains( p, geoid ); } /* Minimum distance to p. */ templateclass Array> double RegionT::Distance( const Point& p, const Geoid* geoid /*=0*/ ) const { assert( !IsEmpty() ); // subsumes defined assert( p.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." <::max(); for( int i = 0; i < Size(); i++ ) { Get( i, hs ); if( hs.IsLeftDomPoint() ) result = MIN( result, hs.Distance( p, geoid ) ); } return result; } /* Minimum distance to r. */ templateclass Array> double RegionT::Distance( const Rectangle<2>& r, const Geoid* geoid /*=0*/ ) const { assert( !IsEmpty() ); // subsumes defined assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." <::max(); for(int i=0;iclass Array> bool RegionT::Intersects( const Rectangle<2>& r, const Geoid* geoid /*=0*/ ) const{ if(!IsDefined() || !r.IsDefined()){ return false; } if(IsEmpty() || r.IsEmpty()){ return false; } // either, the rectangle is contained in the region // or one of the halfsegments of the region // intersects the rectangle Point p1(true,r.MinD(0),r.MinD(1)); Point p2(true,r.MaxD(0),r.MinD(1)); Point p3(true,r.MaxD(0),r.MaxD(1)); Point p4(true,r.MinD(0),r.MaxD(1)); if(Contains(p1,geoid)) return true; if(Contains(p2,geoid)) return true; if(Contains(p3,geoid)) return true; if(Contains(p4,geoid)) return true; HalfSegment hs; for(int i=0;iclass Array> double RegionT::Area(const Geoid* geoid/*=0*/) const { assert( IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ std::cerr << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." << std::endl; //TODO: Implement spherical geometry case. assert(false); } int n = Size(); double area = 0.0, x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0; // get minimum with respect to Y-dimension double minY = MIN(BoundingBox().MinD(1), +0.0); HalfSegment hs; for(int i=0; i= 0, so we correct them y0 = hs.GetLeftPoint().GetY() - minY; y1 = hs.GetRightPoint().GetY() - minY; double a = (x1-x0) * ((y1+y0) * 0.5); if ( hs.attr.insideAbove ){ a = -a; } area += a; } } return area; } /* Distance to other spatial types. */ templateclass Array> templateclass Array2> double RegionT::Distance( const PointsT& ps, const Geoid* geoid /*=0*/ ) const { assert( !IsEmpty() ); // subsumes IsDefined() assert( !ps.IsEmpty() ); // subsumes IsDefined() assert( IsOrdered() ); assert( ps.IsOrdered() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." <::max(); Point p(true); for( int i = 0; i < ps.Size(); i++ ){ ps.Get( i, p ); if( Contains( p ) ){ return 0.0; } HalfSegment hs; for( int j = 0; j < Size(); j++ ){ Get( j, hs ); if( hs.IsLeftDomPoint() ) result = MIN( result, hs.Distance( p, geoid ) ); } } return result; } templateclass Array> templateclass Array2> double RegionT::Distance( const RegionT &r, const Geoid* geoid /*=0*/ ) const { assert( !IsEmpty() ); // subsumes IsDefined() assert( !r.IsEmpty() ); // subsumes IsDefined() assert( IsOrdered() ); assert( r.IsOrdered() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." <::max(); HalfSegment 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( hs1.Intersects( hs2, geoid ) ){ return 0.0; } result = MIN( result, hs1.Distance( hs2, geoid ) ); } } } } return result; } /* Divides this region into their faces. */ templateclass Array> templateclass Array2> void RegionT::Components( std::vector*>& components ) { components.clear(); if( IsEmpty() ) { // subsumes IsDefined() return; } for(int i=0;i(1)); components[i]->StartBulkLoad(); } for(int i=0;iattr.faceno; hs->attr.faceno = 0; (*components[face]) += *hs; delete hs; } for(int i=0;iEndBulkLoad(false,false,false,false); } } /* Returns the holes of this region. */ templateclass Array> templateclass Array2> void RegionT::getHoles(RegionT& result) const{ if(!IsDefined()){ result.SetDefined(false); } result.Clear(); result.SetDefined(true); result.StartBulkLoad(); int edgeno = 0; for(int i=0; i< Size(); i++){ HalfSegment 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.EndBulkLoad(true,true,true,true); } /* Affine transformations. */ templateclass Array> templateclass Array2> void RegionT::Translate( const Coord& x, const Coord& y, RegionT& result ) const { result.Clear(); if( !IsDefined() ) { result.SetDefined( false ); return; } result.SetDefined( true ); assert( IsOrdered() ); HalfSegment hs; result.StartBulkLoad(); for( int i = 0; i < Size(); i++ ) { Get( i, hs ); hs.Translate( x, y ); result += hs; } result.SetNoComponents( NoComponents() ); result.EndBulkLoad( false, false, false, false ); } templateclass Array> templateclass Array2> void RegionT::Rotate( const Coord& x, const Coord& y, const double alpha, RegionT& result ) const { result.Clear(); if( !IsDefined() ) { result.SetDefined( false ); return; } result.Resize(Size()); result.SetDefined( true ); double s = sin(alpha); double c = cos(alpha); double m00 = c; double m01 = -s; double m02 = x - x*c + y*s; double m10 = s; double m11 = c; double m12 = y - x*s-y*c; result.StartBulkLoad(); HalfSegment hso; Point p1(true); Point p2(true); Point p1o(true); Point p2o(true); for( int i = 0; i < Size(); i++ ) { Get( i, hso ); p1o = hso.GetLeftPoint(); p2o = hso.GetRightPoint(); p1.Set( m00*p1o.GetX() + m01*p1o.GetY() + m02, m10*p1o.GetX() + m11*p1o.GetY() + m12); p2.Set( m00*p2o.GetX() + m01*p2o.GetY() + m02, m10*p2o.GetX() + m11*p2o.GetY() + m12); HalfSegment hsr(hso); // ensure to copy attr; hsr.Set(hso.IsLeftDomPoint(),p1,p2); bool above = hso.attr.insideAbove; if(p1>p2) { above = !above; } hsr.attr.insideAbove = above; result += hsr; } result.EndBulkLoad(true,true,true,false); // reordering may be required } templateclass Array> templateclass Array2> void RegionT::Scale( const Coord& sx, const Coord& sy, RegionT& result ) const { result.Clear(); if( !IsDefined() ) { result.SetDefined( false ); return; } result.Resize(Size()); result.SetDefined( true ); result.StartBulkLoad(); HalfSegment hso; for( int i = 0; i < Size(); i++ ) { Get( i, hso ); if(!hso.Scale(sx,sy)){ result.Clear(); result.SetDefined(false); return; } result += hso; } result.EndBulkLoad(); // reordering may be required } /* Computres touchpooints with l. */ templateclass Array> templateclass Array2, templateclass Array3> void RegionT::TouchPoints( const LineT& l, PointsT& result, const Geoid* geoid/*=0*/ ) const { result.Clear(); if( !IsDefined() || !l.IsDefined() || (geoid && !geoid->IsDefined()) ) { result.SetDefined( false ); return; } result.SetDefined( true ); if( IsEmpty() || l.IsEmpty() ) { return; } assert( IsOrdered() && l.IsOrdered() ); HalfSegment hs1, hs2; Point p(true); result.StartBulkLoad(); for( int i = 0; i < Size(); i++ ){ Get( i, hs1 ); if( hs1.IsLeftDomPoint() ){ for( int j = 0; j < l.Size(); j++ ){ l.Get( j, hs2 ); if( hs2.IsLeftDomPoint() ){ if( hs1.Intersection( hs2, p, geoid ) ) { result += p; } } } } } result.EndBulkLoad(); } templateclass Array> templateclass Array2, templateclass Array3> void RegionT::TouchPoints( const RegionT& r, PointsT& result, const Geoid* geoid/*=0*/ ) const { result.Clear(); if( !IsDefined() || !r.IsDefined() || (geoid && !geoid->IsDefined()) ) { result.SetDefined( false ); return; } result.SetDefined( true ); if( IsEmpty() || r.IsEmpty() ){ return; } assert( IsOrdered() && r.IsOrdered() ); HalfSegment hs1, hs2; Point p(false); result.StartBulkLoad(); 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( hs1.Intersection( hs2, p, geoid ) ){ result += p; } } } } } result.EndBulkLoad( true); } /* Computes the common part of the boundary. */ templateclass Array> templateclass Array2, templateclass Array3> void RegionT::CommonBorder( const RegionT& r, LineT& result, const Geoid* geoid/*=0*/ ) const { result.Clear(); if( !IsDefined() || !r.IsDefined() || (geoid && !geoid->IsDefined()) ) { result.SetDefined( false ); return; } result.SetDefined( true ); if( IsEmpty() || r.IsEmpty() ){ return; } assert( IsOrdered() && r.IsOrdered() ); HalfSegment hs1, hs2; HalfSegment reshs; int edgeno = 0; Point p(true); result.StartBulkLoad(); 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( hs1.Intersection( hs2, reshs, geoid ) ){ reshs.attr.edgeno = edgeno++; result += reshs; reshs.SetLeftDomPoint( !reshs.IsLeftDomPoint() ); result += reshs; } } } } } result.EndBulkLoad(); } /* returns the number of components. */ templateclass Array> int RegionT::NoComponents() const { assert( IsDefined() ); return noComponents; } /* Returns all points of the containes halfsegments. */ templateclass Array> templateclass Array2> void RegionT::Vertices( PointsT* result, const Geoid* geoid/*=0*/ ) const { result->Clear(); if(!IsDefined() || (geoid && !geoid->IsDefined()) ){ result->SetDefined(false); return; } result->SetDefined(true); if( IsEmpty() ){ return; } assert( IsOrdered() ); HalfSegment hs; int size = Size(); for( int i = 0; i < size; i++ ){ Get( i, hs ); Point p = hs.GetDomPoint(); *result += p; } result->EndBulkLoad( false, true ); } /* Computes the boundary of this region. */ templateclass Array> templateclass Array2> void RegionT::Boundary( LineT* result, const Geoid* geoid/*=0*/ ) const { result->Clear(); if(!IsDefined() || (geoid && !geoid->IsDefined()) ){ result->SetDefined(false); return; } assert( IsOrdered() ); result->SetDefined(true); if( IsEmpty() ){ return; } HalfSegment hs; result->StartBulkLoad(); int size = Size(); for( int i = 0; i < size; i++ ){ Get( i, hs ); if(hs.IsLeftDomPoint()){ hs.attr.edgeno = i; *result += hs; hs.SetLeftDomPoint(false); *result += hs; } } result->EndBulkLoad(); } /* Assignment operator. */ templateclass Array> templateclass Array2> RegionT& RegionT::operator=( const RegionT& r ) { assert( r.IsOrdered() ); convertDbArrays(r.region, region); bbox = r.bbox; noComponents = r.noComponents; del.isDefined = r.del.isDefined; return *this; } templateclass Array> RegionT& RegionT::operator=( const RegionT& r ) { assert( r.IsOrdered() ); region.copyFrom(r.region); bbox = r.bbox; noComponents = r.noComponents; del.isDefined = r.del.isDefined; return *this; } /* auxiliary functions for parallel scan through 2 regions. */ templateclass Array2, templateclass Array3> void SelectFirst_rr( const RegionT& R1, const RegionT& R2, object& obj, status& stat ) { R1.SelectFirst(); R2.SelectFirst(); HalfSegment hs1, hs2; bool gotHs1 = R1.GetHs( hs1 ), gotHs2 = R2.GetHs( hs2 ); if( !gotHs1 && !gotHs2 ) { obj = none; stat = endboth; } else if( !gotHs1 ) { obj = second; stat = endfirst; } else if( !gotHs2 ) { obj = first; stat = endsecond; } else //both defined { stat = endnone; if( hs1 < hs2 ) obj = first; else if( hs1 > hs2 ) obj = second; else obj=both; } } templateclass Array2, templateclass Array3> void SelectNext_rr( const RegionT& R1, const RegionT& R2, object& obj, status& stat ) { // 1. get the current elements HalfSegment hs1, hs2; bool gotHs1 = R1.GetHs( hs1 ), gotHs2 = R2.GetHs( hs2 ); //2. move the pointers if( !gotHs1 && !gotHs2 ) { //do nothing } else if( !gotHs1 ) { R2.SelectNext(); gotHs2 = R2.GetHs( hs2 ); } else if( !gotHs2 ) { R1.SelectNext(); gotHs1 = R1.GetHs( hs1 ); } else //both currently defined { if( hs1 < hs2 ) //then hs1 is the last output { R1.SelectNext(); gotHs1 = R1.GetHs( hs1 ); } else if( hs1 > hs2 ) { R2.SelectNext(); gotHs2 = R2.GetHs( hs2 ); } else { R1.SelectNext(); gotHs1 = R1.GetHs( hs1 ); R2.SelectNext(); gotHs2 = R2.GetHs( hs2 ); } } //3. generate the outputs if( !gotHs1 && !gotHs2 ) { obj = none; stat = endboth; } else if( !gotHs1 ) { obj = second; stat = endfirst; } else if( !gotHs2 ) { obj = first; stat = endsecond; } else //both defined { stat = endnone; if( hs1 < hs2 ) obj = first; else if( hs1 > hs2 ) obj = second; else obj = both; } } /* Check for equality. */ templateclass Array> bool RegionT::operator==( const RegionT& r ) const { if(!IsDefined() && !r.IsDefined()){ return true; } if(!IsDefined() || !r.IsDefined()){ return false; } if( Size() != r.Size() ) return false; if( IsEmpty() && r.IsEmpty() ) return true; if( bbox != r.bbox ) return false; assert( ordered && r.ordered ); object obj; status stat; SelectFirst_rr( *this, r, obj, stat ); while( obj == both || obj == none ) { if( stat == endboth ) return true; SelectNext_rr( *this, r, obj, stat ); } return false; } templateclass Array> bool RegionT::operator!=( const RegionT &cr) const { return !(*this==cr); } /* Adding and subtracting halfsegments. */ templateclass Array> RegionT& RegionT::operator+=( const HalfSegment& hs ) { assert(IsDefined()); if( IsEmpty() ) bbox = hs.BoundingBox(); else bbox = bbox.Union( hs.BoundingBox() ); if( !IsOrdered() ) { region.Append(hs); } else { int pos; if( !Find( hs, pos ) ) { HalfSegment auxhs; for( int i = region.Size() - 1; i >= pos; i++ ) { region.Get( i, auxhs ); region.Put( i+1, auxhs ); } region.Put( pos, hs ); } } return *this; } templateclass Array> RegionT& RegionT::operator-=( const HalfSegment& hs ) { assert(IsDefined()); assert( IsOrdered() ); int pos; if( Find( hs, pos ) ) { HalfSegment auxhs; for( int i = pos; i < Size(); i++ ) { region.Get( i+1, auxhs ); region.Put( i, auxhs ); } } // Naive way to redo the bounding box. if( IsEmpty() ) bbox.SetDefined( false ); int i = 0; HalfSegment auxhs; region.Get( i++, auxhs ); bbox = auxhs.BoundingBox(); for( ; i < Size(); i++ ) { region.Get( i, auxhs ); bbox = bbox.Union( auxhs.BoundingBox() ); } return *this; } /* Searches the index of a speified halfsegmnst. */ templateclass Array> bool RegionT::Find( const HalfSegment& hs, int& pos ) const { assert( IsOrdered() ); assert(IsDefined()); return region.Find( &hs, HalfSegmentCompare, pos ); } templateclass Array> bool RegionT::Find( const Point& p, int& pos ) const { assert( IsOrdered() ); assert( IsDefined()); return region.Find( &p, PointHalfSegmentCompare, pos ); } templateclass Array> void RegionT::Sort() { if(!IsDefined()){ return; } assert( !IsOrdered() ); region.Sort( HalfSegmentCompare ); ordered = true; } int HalfSegmentLogicCompare(const void *a, const void *b); templateclass Array> void RegionT::LogicSort() { if(!IsDefined()){ return; } region.Sort( HalfSegmentLogicCompare ); ordered = true; } templateclass Array> std::ostream& operator<<( std::ostream& os, const RegionT& cr ) { os << "<"<"; return os; } /* Sets the partner numbers. Is is assumed, that corresponding edges have the same edgeno, */ templateclass Array> void RegionT::SetPartnerNo() { if( !IsDefined() ) return; int size = Size(); int* tmp = new int[size/2]; memset(tmp,0,size*sizeof(int) / 2); HalfSegment 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]; HalfSegment hs1( hs ); hs1.attr.partnerno = p; Put( i, hs1 ); Get( p, hs ); hs1 = hs; hs1.attr.partnerno = i; Put( p, hs1 ); } } delete[] tmp; } bool GetAcceptedPoint( std::vector pointsOnEdge, int &i, const int end, EdgePoint &ep ); templateclass Array> templateclass Array2> void RegionT::CreateNewSegments(std::vectorpointsOnEdge, RegionT &cr, const Point &bPoint,const Point &ePoint, WindowEdge edge,int &partnerno, bool inside, const Geoid* geoid/*=0*/) //The inside attribute indicates if the points on edge will originate //segments that are inside the window (its values is true), or outside //the window (its value is false) { int begin, end, i; HalfSegment *hs; AttrType attr(0); EdgePoint dp,dpAux; if (pointsOnEdge.size()==0) return; /* for (int j=0;jSetAttr(attr); cr+=(*hs); hs->SetLeftDomPoint( !hs->IsLeftDomPoint() ); cr+=(*hs); delete hs; } begin++; //The variable ~begin~ must be incremented until exists // points with the same coordinates //and directions as dp while (begin<=end) { dpAux = pointsOnEdge[begin]; if (!( (dpAux.GetX() == dp.GetX()) && (dpAux.GetY() == dp.GetY()) && (dpAux.direction==dp.direction) ) ) break; begin++; } } dp = pointsOnEdge[end]; if ( !dp.direction) //dp points to right or up { bool rejectEndPoint=dp.rejected; end--; while ( end >= begin ) { dpAux = pointsOnEdge[end]; if ( !( (dpAux.GetX() == dp.GetX() ) && ( dpAux.GetY() == dp.GetY() ) && (dpAux.direction==dp.direction) ) ) break; //when a rejected point is found the rejectEndPoint //does not change anymore. end--; } if (!rejectEndPoint) { hs = new HalfSegment(true, dp, ePoint); attr.partnerno = partnerno; if ( (edge == WTOP) || (edge == WLEFT) ) attr.insideAbove = !inside; else if ( (edge == WRIGHT) || (edge == WBOTTOM)) attr.insideAbove = inside; partnerno++; hs->SetAttr(attr); cr+=(*hs); hs->SetLeftDomPoint( !hs->IsLeftDomPoint() ); cr+=(*hs); delete hs; } } i = begin; while (i < end) { EdgePoint ep1,ep2; if ( GetAcceptedPoint(pointsOnEdge,i,end,ep1) ) { i++; if (GetAcceptedPoint(pointsOnEdge,i,end, ep2) ) i++; else break; } else break; if ( ! ( (ep1.GetX() == ep2.GetX()) && (ep1.GetY() == ep2.GetY()) ) ) { //discard degenerated edges hs = new HalfSegment(true, ep1, ep2); attr.partnerno = partnerno; partnerno++; if ( (edge == WTOP) || (edge == WLEFT) ) attr.insideAbove = !inside; else if ( (edge == WRIGHT) || (edge == WBOTTOM)) attr.insideAbove = inside; hs->SetAttr(attr); cr+=(*hs); hs->SetLeftDomPoint( !hs->IsLeftDomPoint() ); cr+=(*hs); delete hs; } } } templateclass Array> templateclass Array2> void RegionT::CreateNewSegmentsWindowVertices(const Rectangle<2> &window, std::vector pointsOnEdge[4], RegionT &cr, int &partnerno,bool inside, const Geoid* geoid/*=0*/) const //The inside attribute indicates if the points on edge will originate //segments that are inside the window (its values is true), or outside //the window (its value is false) { Point tlPoint(true,window.MinD(0),window.MaxD(1)), trPoint(true,window.MaxD(0),window.MaxD(1)), blPoint(true,window.MinD(0),window.MinD(1)), brPoint(true,window.MaxD(0),window.MinD(1)); bool tl=false, tr=false, bl=false, br=false; AttrType attr(0); if ( ( (pointsOnEdge[WTOP].size()==0) || (pointsOnEdge[WLEFT].size()==0) ) && ( this->Contains(tlPoint,geoid) ) ){ tl = true; } if ( ( (pointsOnEdge[WTOP].size()==0) || (pointsOnEdge[WRIGHT].size()==0) ) && ( this->Contains(trPoint,geoid) ) ){ tr = true; } if ( ( (pointsOnEdge[WBOTTOM].size()==0) || (pointsOnEdge[WLEFT].size()==0) ) && ( this->Contains(blPoint,geoid) ) ){ bl = true; } if ( ( (pointsOnEdge[WBOTTOM].size()==0) || (pointsOnEdge[WRIGHT].size()==0) ) && ( this->Contains(brPoint,geoid) ) ){ br = true; } //Create top edge if (tl && tr && (pointsOnEdge[WTOP].size()==0)){ HalfSegment *hs; hs = new HalfSegment(true, tlPoint, trPoint); //If inside == true, then insideAbove attribute of the top and left //half segments must be set to false, otherwise its value must be true. //In other words, the insideAbove atribute value is the opposite of the //inside function's parameter value. attr.insideAbove = !inside; attr.partnerno = partnerno; partnerno++; hs->SetAttr(attr); cr+=(*hs); hs->SetLeftDomPoint( !hs->IsLeftDomPoint() ); cr+=(*hs); delete hs; } //Create left edge if (tl && bl && (pointsOnEdge[WLEFT].size()==0)){ HalfSegment *hs; hs = new HalfSegment(true, tlPoint, blPoint); //If inside == true, then insideAbove attribute of the top and left //half segments must be set to false, otherwise its value must be true. //In other words, the insideAbove atribute value is the opposite of the //parameter inside's value. attr.insideAbove = !inside; attr.partnerno = partnerno; partnerno++; hs->SetAttr(attr); cr+=(*hs); hs->SetLeftDomPoint( !hs->IsLeftDomPoint() ); cr+=(*hs); delete hs; } //Create right edge if (tr && br && (pointsOnEdge[WRIGHT].size()==0)){ HalfSegment *hs; hs = new HalfSegment(true, trPoint, brPoint); //If inside == true, then insideAbove attribute of the right and bottom //half segments must be set to true, otherwise its value must be false. //In other words, the insideAbove atribute value is the same of the //parameter inside's value. attr.insideAbove = inside; attr.partnerno = partnerno; partnerno++; hs->SetAttr(attr); cr+=(*hs); hs->SetLeftDomPoint( !hs->IsLeftDomPoint() ); cr+=(*hs); delete hs; } //Create bottom edge if (bl && br && (pointsOnEdge[WBOTTOM].size()==0)){ HalfSegment *hs; hs = new HalfSegment(true, blPoint, brPoint); //If inside == true, then insideAbove attribute of the right and bottom //half segments must be set to true, otherwise its value must be false. //In other words, the insideAbove atribute value is the same of the //parameter inside's value. attr.insideAbove = inside; attr.partnerno = partnerno; partnerno++; hs->SetAttr(attr); cr+=(*hs); hs->SetLeftDomPoint( !hs->IsLeftDomPoint() ); cr+=(*hs); delete hs; } } templateclass Array> bool RegionT::ClippedHSOnEdge(const Rectangle<2> &window, const HalfSegment &hs, bool clippingIn,std::vector pointsOnEdge[4], const Geoid* geoid/*=0*/) { //This function returns true if the segment lies on one of the window's edge. // The clipped half segments that lie on the edges must be rejected according to // the kind of clipping (returning the portion of the region that is inside the // region or the portion that is outside). EdgePoint ep1,ep2; AttrType attr=hs.GetAttr(); bool reject = false, result = false; //Returns true if the clipped hs was treated as a segment on edge if ( hs.GetLeftPoint().GetY() == hs.GetRightPoint().GetY() ) { //horizontal edge if (( hs.GetLeftPoint().GetY() == window.MaxD(1) ) ) { //top edge // If the half segment lies on the upper edge and // the insideAbove attribute's value // is true then the region's area is outside the window, // and the half segment mustn't // be included in the clipped region (Reject). // However, its end points maybe will have to be // connected to the vertices of the window. // It happens only when the vertice of the // window is inside the region and the end point // is the first point on the window's // edge (for the upper-left vertice) or the last // point on the window's vertice (for // the upper right edge). if ( clippingIn && attr.insideAbove ) reject = true; else if ( !clippingIn && !attr.insideAbove ) reject = true; ep1.Set(hs.GetLeftPoint(),false,reject); //--> right ep2.Set(hs.GetRightPoint(),true,reject); //<-- left pointsOnEdge[WTOP].push_back(ep1); pointsOnEdge[WTOP].push_back(ep2); result = true; } else //bottom edge if (( hs.GetLeftPoint().GetY() == window.MinD(1) ) ) { if ( clippingIn && !attr.insideAbove ) reject = true; else if ( !clippingIn && attr.insideAbove ) reject = true; ep1.Set(hs.GetLeftPoint(),false,reject); //--> right ep2.Set(hs.GetRightPoint(),true,reject); //<-- left pointsOnEdge[WBOTTOM].push_back(ep1); pointsOnEdge[WBOTTOM].push_back(ep2); result = true; } } else //Vertical edges if ( hs.GetLeftPoint().GetX() == hs.GetRightPoint().GetX() ) { if ( hs.GetLeftPoint().GetX() == window.MinD(0) ) //Left edge { if ( clippingIn && attr.insideAbove ) reject = true; else if (!clippingIn && !attr.insideAbove ) reject = true; ep1.Set(hs.GetLeftPoint(),false,reject); //^ up ep2.Set(hs.GetRightPoint(),true,reject); //v dowb pointsOnEdge[WLEFT].push_back(ep1); pointsOnEdge[WLEFT].push_back(ep2); result = true; } else if ( hs.GetLeftPoint().GetX() == window.MaxD(0) ) //Right edge { if ( clippingIn && !attr.insideAbove ) reject = true; else if ( !clippingIn && attr.insideAbove ) reject = true; ep1.Set(hs.GetLeftPoint(),false,reject); //^ up ep2.Set(hs.GetRightPoint(),true,reject); //v dowb pointsOnEdge[WRIGHT].push_back(ep1); pointsOnEdge[WRIGHT].push_back(ep2); result = true; } } return result; } templateclass Array> bool RegionT::GetCycleDirection( const Point &pA, const Point &pP, const Point &pB ) { double m_p_a,m_p_b; if (pA.GetX() == pP.GetX()){//A --> P is a vertical segment if (pA.GetY() > pP.GetY() ) {//A --> P directed downwards (case 1) return false; //Counterclockwise } else {//upwards (case 2) return true; // Clockwise } } if (pB.GetX() == pP.GetX()) {//P --> B is a vertical segment if ( pP.GetY() > pB.GetY()){ //downwords (case 3) return false; //Conterclockwise } else {//upwards return true; //Clockwise } } //compute the slopes of P-->A and P-->B m_p_a = ( pA.GetY() - pP.GetY() ) / ( pA.GetX() - pP.GetX() ); m_p_b = ( pB.GetY() - pP.GetY() ) / ( pB.GetX() - pP.GetX() ); if (m_p_a > m_p_b) //case 5 return false;//counterclockwise else //case 6 return true; //clockwise } templateclass Array> bool RegionT::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. */ Point pA(true,0,0), pP(true,0,0), pB(true,0,0); HalfSegment 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(); } return GetCycleDirection(pA,pP,pB); } //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). void AddPointToEdgeArray( const Point &p, const HalfSegment &hs, const Rectangle<2> &window, std::vector pointsOnEdge[4] ); templateclass Array> templateclass Array2> void RegionT::GetClippedHSIn(const Rectangle<2> &window, RegionT &clippedRegion, std::vector pointsOnEdge[4], int &partnerno, const Geoid* geoid/*=0*/) const { HalfSegment hs; HalfSegment hsInside; bool inside, isIntersectionPoint; SelectFirst(); for(int i=0; i < Size(); i++){ GetHs( hs ); if (hs.IsLeftDomPoint()){ Point intersectionPoint; hs.WindowClippingIn(window, hsInside, inside, isIntersectionPoint,intersectionPoint,geoid); if (isIntersectionPoint){ AddPointToEdgeArray(intersectionPoint,hs,window, pointsOnEdge); } else if ( inside ) { bool hsOnEdge = ClippedHSOnEdge(window,hsInside,true, pointsOnEdge,geoid); if (!hsOnEdge){ //Add the clipped segment to the new region if it was not rejected hsInside.attr.partnerno=partnerno; partnerno++; hsInside.SetAttr(hsInside.attr); clippedRegion += hsInside; hsInside.SetLeftDomPoint( !hsInside.IsLeftDomPoint() ); clippedRegion += hsInside; //Add the points to the array of the points that lie on //some of the window's edges const Point& lp = hsInside.GetLeftPoint(), rp = hsInside.GetRightPoint(); //If the point lies on one edge it must be added to the //corresponding vector. AddPointToEdgeArray(lp,hs,window, pointsOnEdge); AddPointToEdgeArray(rp, hs,window, pointsOnEdge); } } } SelectNext(); } } templateclass Array> void RegionT::AddClippedHS( const Point &pl, const Point &pr, AttrType &attr, int &partnerno ) { HalfSegment hs(true,pl,pr); attr.partnerno = partnerno; partnerno++; hs.SetAttr(attr); (*this)+=hs; hs.SetLeftDomPoint( !hs.IsLeftDomPoint() ); (*this)+=hs; } templateclass Array> templateclass Array2> void RegionT::GetClippedHSOut(const Rectangle<2> &window, RegionT &clippedRegion, std::vector pointsOnEdge[4], int &partnerno, const Geoid* geoid/*=0*/) const { for (int i=0; i < Size();i++){ HalfSegment hs; HalfSegment hsInside; bool inside=false,isIntersectionPoint=false; Get(i,hs); if (hs.IsLeftDomPoint()){ Point intersectionPoint; hs.WindowClippingIn(window,hsInside, inside, isIntersectionPoint,intersectionPoint,geoid); if (inside){ bool hsOnEdge=false; if (isIntersectionPoint){ HalfSegment aux( hs ); if (hs.GetLeftPoint()!=intersectionPoint) clippedRegion.AddClippedHS(aux.GetLeftPoint(), intersectionPoint, aux.attr,partnerno) ; if (hs.GetRightPoint()!=intersectionPoint) clippedRegion.AddClippedHS(intersectionPoint, aux.GetRightPoint(), aux.attr,partnerno); AddPointToEdgeArray(intersectionPoint,aux, window, pointsOnEdge); } else { hsOnEdge = ClippedHSOnEdge(window, hsInside, false, pointsOnEdge, geoid); if (!hsOnEdge){ HalfSegment aux( hs ); if (hs.GetLeftPoint()!=hsInside.GetLeftPoint()){ //Add the part of the half segment composed by the left //point of hs and the left point of hsInside. clippedRegion.AddClippedHS(aux.GetLeftPoint(), hsInside.GetLeftPoint(), aux.attr,partnerno); } AddPointToEdgeArray(hsInside.GetLeftPoint(),aux, window, pointsOnEdge); if (hs.GetRightPoint()!=hsInside.GetRightPoint()){ //Add the part of the half segment composed by the right //point of hs and the right point of hsInside. clippedRegion.AddClippedHS(hsInside.GetRightPoint(), aux.GetRightPoint(), aux.attr,partnerno); } AddPointToEdgeArray(hsInside.GetRightPoint(),aux, window, pointsOnEdge); } } } else { HalfSegment aux( hs ); clippedRegion.AddClippedHS(aux.GetLeftPoint(), aux.GetRightPoint(), aux.attr,partnerno); } } SelectNext(); } } templateclass Array> templateclass Array2> void RegionT::GetClippedHS(const Rectangle<2> &window, RegionT &clippedRegion, bool inside, const Geoid* geoid/*=0*/) const { std::vector pointsOnEdge[4]; //upper edge, right edge, bottom, left int partnerno=0; clippedRegion.StartBulkLoad(); if (inside){ GetClippedHSIn(window,clippedRegion,pointsOnEdge,partnerno); } else { GetClippedHSOut(window,clippedRegion,pointsOnEdge,partnerno); } Point bPoint,ePoint; bPoint.Set(window.MinD(0),window.MaxD(1)); //left-top ePoint.Set(window.MaxD(0),window.MaxD(1)); //right-top CreateNewSegments(pointsOnEdge[WTOP],clippedRegion,bPoint,ePoint, WTOP,partnerno,inside); bPoint.Set(window.MinD(0),window.MinD(1)); //left-bottom ePoint.Set(window.MaxD(0),window.MinD(1)); //right-bottom CreateNewSegments(pointsOnEdge[WBOTTOM],clippedRegion,bPoint,ePoint, WBOTTOM,partnerno,inside); bPoint.Set(window.MinD(0),window.MinD(1)); //left-bottom ePoint.Set(window.MinD(0),window.MaxD(1)); //left-top CreateNewSegments(pointsOnEdge[WLEFT],clippedRegion,bPoint,ePoint, WLEFT,partnerno,inside); bPoint.Set(window.MaxD(0),window.MinD(1)); //right-bottom ePoint.Set(window.MaxD(0),window.MaxD(1)); //right-top CreateNewSegments(pointsOnEdge[WRIGHT],clippedRegion,bPoint,ePoint, WRIGHT,partnerno,inside); CreateNewSegmentsWindowVertices(window, pointsOnEdge,clippedRegion, partnerno,inside); clippedRegion.EndBulkLoad(); } templateclass Array> bool RegionT::IsCriticalPoint( const Point &adjacentPoint, const int hsPosition ) const { int adjPosition = hsPosition, adjacencyNo = 0, step = 1; do { HalfSegment adjCHS; adjPosition+=step; if ( adjPosition<0 || adjPosition>=this->Size()) break; Get(adjPosition,adjCHS); 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); } templateclass Array> bool RegionT::GetAdjacentHS( const HalfSegment &hs, const int hsPosition, int &position, const int partnerno, const int partnernoP, HalfSegment& adjacentCHS, const Point &adjacentPoint, Point &newAdjacentPoint, bool *cycle, int step) const { bool adjacencyFound=false; do { position+=step; if ( position<0 || position>=this->Size()){ // no halfsegments found in this direction break; } Get(position,adjacentCHS); if (partnernoP == position){ // back direction of the original 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); // cout<<"adjacencyFound "<class Array> void RegionT::ComputeCycle( HalfSegment &hs, int faceno, int cycleno, int &edgeno, bool *cycle ) { Point nextPoint = hs.GetLeftPoint(), lastPoint = hs.GetRightPoint(), previousPoint, currentCriticalPoint(false); AttrType attr, attrP; HalfSegment hsP; std::vector sCycleVector; SCycle *s=NULL; do { if (s==NULL) { //Update attributes attr = hs.GetAttr(); Get(attr.partnerno,hsP); attrP = hsP.GetAttr(); attr.faceno=faceno; attr.cycleno=cycleno; attr.edgeno=edgeno; UpdateAttr(attrP.partnerno,attr); attrP.faceno=faceno; attrP.cycleno=cycleno; attrP.edgeno=edgeno; UpdateAttr(attr.partnerno,attrP); edgeno++; cycle[attr.partnerno]=true; cycle[attrP.partnerno]=true; if (this->IsCriticalPoint(nextPoint,attrP.partnerno)) { currentCriticalPoint = nextPoint; } s = new SCycle(hs,attr.partnerno,hsP,attrP.partnerno, currentCriticalPoint,nextPoint); } HalfSegment adjacentCHS; Point 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; // cout<<"flag 1 "<goToCHS1Left ) { s->goToCHS1Left=GetAdjacentHS(s->hs1, s->hs2Partnerno, s->hs1PosLeft, s->hs1Partnerno, s->hs2Partnerno, adjacentCHS, previousPoint, nextPoint, cycle, -1); adjacentPointFound=s->goToCHS1Left; //cout<<"flag 2 "<goToCHS2Right) { s->goToCHS2Right=GetAdjacentHS(s->hs2, s->hs1Partnerno, s->hs2PosRight, s->hs2Partnerno, s->hs1Partnerno, adjacentCHS, previousPoint, nextPoint, cycle, 1); adjacentPointFound=s->goToCHS2Right; //cout<<"flag 3 "<goToCHS2Left) { s->goToCHS2Left=GetAdjacentHS(s->hs2, s->hs1Partnerno, s->hs2PosLeft, s->hs2Partnerno, s->hs1Partnerno, adjacentCHS, previousPoint, nextPoint, cycle, -1); adjacentPointFound = s->goToCHS2Left; // cout<<"flag 4 "<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 SCycle(firstSCycle); } else{ if(s){ delete s; } s= new SCycle(sAux); } hs = s->hs1; currentCriticalPoint=s->criticalPoint; nextPoint=s->nextPoint; continue; } if ( nextPoint==lastPoint ) { //Update attributes attr = adjacentCHS.GetAttr(); Get(attr.partnerno,hsP); attrP = hsP.GetAttr(); attr.faceno=faceno; attr.cycleno=cycleno; attr.edgeno=edgeno; UpdateAttr(attrP.partnerno,attr); attrP.faceno=faceno; attrP.cycleno=cycleno; attrP.edgeno=edgeno; UpdateAttr(attr.partnerno,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; } } //This function returns the value of the attribute inside above of //the first half segment under the half segment hsS. templateclass Array> int RegionT::GetNewFaceNo(HalfSegment &hsS, bool *cycle) { int coverno=0; int startpos=0; double y0; AttrType attr; std::vector v; //1. find the right place by binary search Find( hsS, startpos ); int hsVisiteds=0; //2. deal with equal-x hs's //To verify if it is need to deal with this attr = hsS.GetAttr(); coverno = attr.coverageno; //search the region value for coverageno steps int touchedNo=0; HalfSegment hs; const Point& p = hsS.GetLeftPoint(); int i=startpos; while (( i>=0)&&(touchedNoGet(i, hs); hsVisiteds++; if ( (cycle[i]) && (hs.IsLeftDomPoint()) && ( (hs.GetLeftPoint().GetX() <= p.GetX()) && (p.GetX() <= hs.GetRightPoint().GetX()) )) { touchedNo++; if (!hs.RayAbove(p, y0)) v.push_back(hs); } i--; //the iterator } if (v.size()==0) return -1; //the new face number will be the last face number +1 else { sort(v.begin(),v.end()); //The first half segment is the next half segment above hsS HalfSegment hs = v[v.size()-1]; attr = hs.GetAttr(); if (attr.insideAbove) return attr.faceno; //the new cycle is a cycle of the face ~attr.faceno~ else return -1; //new face } } templateclass Array> int RegionT::GetNewFaceNo(const HalfSegment& 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. double y0; double maxY0; HalfSegment hs; HalfSegment maxHS; bool hasMax = false; const Point& p = hsIn.GetLeftPoint(); const int coverno = hsIn.GetAttr().coverageno; int touchedNo = 0; int i = startpos - 1; bool first = true; while (i >=0 && touchedNo < coverno) { Get(i, hs); if (!hs.IsLeftDomPoint()) { i--; continue; } if (hs.GetLeftPoint().GetX() <= p.GetX() && p.GetX() <= hs.GetRightPoint().GetX()) { touchedNo++; } if (!AlmostEqual(hs.GetRightPoint().GetX(), p.GetX()) && hs.RayDown(p, y0)) { if (first || y0 > maxY0 || (AlmostEqual(y0, maxY0) && 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) { std::cerr << "Problem in rebuilding cycle in a region " << std::endl; std::cerr << "No outer cycle found" << std::endl; std::cerr << "hsIn: " << hsIn << std::endl; std::cerr << "Halfsegments : --------------- " << std::endl; HalfSegment hs; for(int i=0;iclass Array> void RegionT::ComputeRegion() { if( !IsDefined() ) return; //array that stores in position i the last cycle number of the face i std::vector 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; HalfSegment hs; 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 int size = Size(); for(int i=0;iclass Array> templateclass Array2> void RegionT::WindowClippingIn(const Rectangle<2> &window, RegionT &clippedRegion, const Geoid* geoid/*=0*/) const { clippedRegion.Clear(); if( !IsDefined() || !window.IsDefined() || (geoid && !geoid->IsDefined()) ) { clippedRegion.SetDefined( false ); return; } clippedRegion.SetDefined( true ); //cout<bbox.Intersects(window,geoid)){ return; } //If the bounding box of the region is inside the window, //then the clippedRegion //is equal to the region been clipped. if (window.Contains(this->bbox,geoid)){ clippedRegion = *this; } else { //cout<bbox<GetClippedHS(window,clippedRegion,true, geoid); //cout<class Array> templateclass Array2> void RegionT::WindowClippingOut(const Rectangle<2> &window, RegionT &clippedRegion, const Geoid* geoid/*=0*/) const { clippedRegion.Clear(); if( !IsDefined() || !window.IsDefined() || (geoid && !geoid->IsDefined()) ) { clippedRegion.SetDefined( false ); return; } clippedRegion.SetDefined( true ); //If the bounding box of the region is inside the window, //then the clipped region is empty //cout<<"region: "<<*this<bbox,geoid)){ return; } if (!window.Intersects(this->bbox,geoid)){ clippedRegion = *this; } else { this->GetClippedHS(window,clippedRegion,false,geoid); // cout<class Array> size_t RegionT::HashValue() const { //cout<<"cregion hashvalue1*******"<class Array> void RegionT::Clear() { region.clean(); pos = -1; ordered = true; bbox.SetDefined(false); } templateclass Array> void RegionT::SetDefined(bool defined) { if(!defined){ Clear(); } Attribute::SetDefined( defined ); } templateclass Array> void RegionT::SetEmpty() { region.clean(); pos = -1; ordered = true; bbox.SetDefined(false); SetDefined(true); } templateclass Array> void RegionT::CopyFrom( const Attribute* right ) { *this = *(const RegionT *)right; } templateclass Array> templateclass Array2> void RegionT::CopyFrom( const RegionT* right ) { *this = *right; } templateclass Array> templateclass Array2> int RegionT::Compare( const RegionT* cr ) const{ if ( !cr ) return -2; if (!IsDefined() && (!cr->IsDefined())){ return 0; } if(!IsDefined()){ return -1; } if(!cr->IsDefined()){ return 1; } if(Size()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; } HalfSegment hs1, hs2; for( int i = 0; i < Size(); i++ ) { Get( i, hs1); cr->Get( i, hs2 ); int hsCmp = hs1.Compare(hs2); if(hsCmp!=0){ return hsCmp; } } return 0; } templateclass Array> int RegionT::Compare( const Attribute* arg ) const { RegionT* cr = (RegionT* )(arg); return Compare(cr); } templateclass Array> std::ostream& RegionT::Print( std::ostream &os ) const { os << "<"; if( !IsDefined() ) { os << " undefined "; } else { HalfSegment hs; for( int i = 0; i < Size(); i++ ) { Get( i, hs ); os << " " << hs; } } os << ">"; return os; } templateclass Array> RegionT *RegionT::Clone() const { return new RegionT( *this); } templateclass Array> bool RegionT::InsertOk( const HalfSegment& hs ) const { HalfSegment auxhs; double dummyy0; // Uncommenting out the following line will increase performance when // bulk importing correct data: // CD: Problem: Database BerlinTest is currently faulty and cannot be // restored when checking is enabled return true; int prevcycleMeet[50]; int prevcyclenum=0; for( int i = 0; i < 50; i++ ) prevcycleMeet[i]=0; for( int i = 0; i<= region.Size()-1; i++ ) { region.Get( i, auxhs ); if (auxhs.IsLeftDomPoint()) { if (hs.Intersects(auxhs)) { if ((hs.attr.faceno!=auxhs.attr.faceno)|| (hs.attr.cycleno!=auxhs.attr.cycleno)) { cout<<"two cycles intersect with the "; cout<<"following edges:"; cout<0) && (auxhs.attr.faceno==hs.attr.faceno) && (auxhs.attr.cycleno!=hs.attr.cycleno)) { if (auxhs.RayAbove(hs.GetLeftPoint(), dummyy0)) { prevcycleMeet[auxhs.attr.cycleno]++; if (prevcyclenum < auxhs.attr.cycleno) prevcyclenum=auxhs.attr.cycleno; } } } } } if ((hs.attr.cycleno>0)) { if (prevcycleMeet[0] % 2 ==0) { cout<<"hole(s) is not inside the outer cycle! "<0) || (hs.attr.cycleno>2))) { HalfSegment hsHoleNEnd, hsHoleNStart; if (region.Size() ==0) return true; int holeNEnd=region.Size()-1; region.Get(holeNEnd, hsHoleNEnd ); if ((hsHoleNEnd.attr.cycleno>1) && ((hs.attr.faceno!=hsHoleNEnd.attr.faceno)|| (hs.attr.cycleno!=hsHoleNEnd.attr.cycleno))) { if (hsHoleNEnd.attr.cycleno>1) { int holeNStart=holeNEnd - 1; region.Get(holeNStart, hsHoleNStart ); while ((hsHoleNStart.attr.faceno==hsHoleNEnd.attr.faceno) && (hsHoleNStart.attr.cycleno==hsHoleNEnd.attr.cycleno)&& (holeNStart>0)) { holeNStart--; region.Get(holeNStart, hsHoleNStart ); } holeNStart++; int prevHolePnt=holeNStart-1; HalfSegment hsPrevHole, hsLastHole; bool stillPrevHole = true; while ((stillPrevHole) && (prevHolePnt>=0)) { region.Get(prevHolePnt, hsPrevHole ); prevHolePnt--; if ((hsPrevHole.attr.faceno!= hsHoleNEnd.attr.faceno)|| (hsPrevHole.attr.cycleno<=0)) { stillPrevHole=false; } if (hsPrevHole.IsLeftDomPoint()) { int holeNMeent=0; for (int i=holeNStart; i<=holeNEnd; i++) { region.Get(i, hsLastHole ); if ((hsLastHole.IsLeftDomPoint())&& (hsLastHole.RayAbove (hsPrevHole.GetLeftPoint(), dummyy0))) holeNMeent++; } if (holeNMeent % 2 !=0) { cout<<"one hole is inside another!!! "< getCycle(const bool isHole, const std::vector& vhs); templateclass Array> std::vector< std::vector > getCycles(const RegionT& reg){ // first step , map halsfsegment according to faceno and cycleno std::map< std::pair , std::vector > m; HalfSegment hs; for(int i=0;i > result; std::map< std::pair , std::vector >::iterator it; for(it=m.begin(); it!=m.end(); it++){ std::pair< std::pair , std::vector > cycleDesc = *it; bool isHole = cycleDesc.first.second > 0; result.push_back(getCycle(isHole, cycleDesc.second)); } return result; } templateclass Array> void RegionT::saveShape(std::ostream& o, uint32_t RecNo) const { // first, write the record header WinUnix::writeBigEndian(o,RecNo); // an empty region if(!IsDefined() || IsEmpty()){ uint32_t length = 2; WinUnix::writeBigEndian(o,length); uint32_t type = 0; WinUnix::writeLittleEndian(o,type); } else { std::vector > cycles = getCycles(*this); uint32_t numParts = cycles.size(); uint32_t numPoints = 0; std::vector >::iterator it; for(it = cycles.begin(); it!=cycles.end(); it++){ numPoints += it->size(); } uint32_t numBytes = 44 + 4 * numParts + 16*numPoints; uint32_t length = numBytes / 2; WinUnix::writeBigEndian(o,length); WinUnix::writeLittleEndian(o,getshpType()); // 4 double minX = getMinX(); double maxX = getMaxX(); double minY = getMinY(); double maxY = getMaxY(); // write the boundig box WinUnix::writeLittle64(o,minX); // 8 * 4 WinUnix::writeLittle64(o,minY); WinUnix::writeLittle64(o,maxX); WinUnix::writeLittle64(o,maxY); WinUnix::writeLittleEndian(o,numParts); WinUnix::writeLittleEndian(o,numPoints); // write the parts uint32_t pos = 0; for(unsigned int i=0; i cycle = cycles[i]; for(unsigned int j=0;jclass Array> void RegionT::writeShape(std::ostream& o, uint32_t RecNo) const { saveShape(o,RecNo); } templateclass Array> template double RegionT::Distance( const LineType &l, const Geoid* geoid /*=0*/ ) const { assert( !IsEmpty() ); // subsumes IsDefined() assert( !l.IsEmpty() ); // subsumes IsDefined() assert( !geoid || geoid->IsDefined() ); if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." << std::endl; assert(false); // TODO: Implement spherical geometry case. } if( IsEmpty() || l.IsEmpty() || (geoid && !geoid->IsDefined()) ) { return -1; } double result = std::numeric_limits::max(); HalfSegment hs1, hs2; for(int i=0; i