/* ---- 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 ---- //[_] [\_] */ #ifndef LineTImpl_H #define LineTImpl_H #include "RegionCreator.h" #include "AVLSegment.h" #include "LineT.h" #include "../../Tools/Flob/MMDbArray.h" #include bool douglas_peucker(const std::vector& orig, // original line const double epsilon, // maximum derivation bool* use, // result const int min, const int max, const bool force, const Geoid* geoid); // current range void douglas_peucker(const std::vector& orig, // original line const double epsilon, // maximum derivation bool* use, // result const bool force, const Geoid* geoid); // current range templateclass Array1, template class Array2> void SelectFirst_ll( const LineT& L1, const LineT& L2, object& obj, status& stat ) { L1.SelectFirst(); L2.SelectFirst(); HalfSegment hs1, hs2; bool gotHs1 = L1.GetHs( hs1 ), gotHs2 = L2.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 Array1, template class Array2> void SelectNext_ll( const LineT& L1, const LineT& L2, object& obj, status& stat ) { // 1. get the current elements HalfSegment hs1, hs2; bool gotHs1 = L1.GetHs( hs1 ), gotHs2 = L2.GetHs( hs2 ); //2. move the pointers if( !gotHs1 && !gotHs2 ) { //do nothing } else if( !gotHs1 ) { L2.SelectNext(); gotHs2 = L2.GetHs( hs2 ); } else if( !gotHs2 ) { L1.SelectNext(); gotHs1 = L1.GetHs( hs1 ); } else //both currently defined { if( hs1 < hs2 ) //then hs1 is the last output { L1.SelectNext(); gotHs1 = L1.GetHs( hs1 ); } else if( hs1 > hs2 ) { L2.SelectNext(); gotHs2 = L2.GetHs( hs2 ); } else { L1.SelectNext(); gotHs1 = L1.GetHs( hs1 ); L2.SelectNext(); gotHs2 = L2.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; } } /* 11.4 Class ~Line~ */ templateclass Array> inline LineT::LineT( const int n ) : StandardSpatialAttribute<2>(true), line( n ), bbox( false ), ordered( true ), noComponents( 0 ), length( 0.0 ), currentHS( -1 ) { } templateclass Array> inline LineT::LineT( const LineT& cl ) : StandardSpatialAttribute<2>(cl.IsDefined()), line( cl.Size() ), bbox( cl.bbox ), ordered( true ), noComponents( cl.noComponents ), length( cl.length ), currentHS ( cl.currentHS) { if(!IsDefined()) return; assert( cl.IsOrdered() ); line.copyFrom(cl.line); } templateclass Array> templateclass Array2> inline LineT::LineT( const LineT& cl ) : StandardSpatialAttribute<2>(cl.IsDefined()), line( cl.Size() ), bbox( cl.bbox ), ordered( true ), noComponents( cl.noComponents ), length( cl.length ), currentHS ( cl.currentHS) { if(!IsDefined()) return; assert( cl.IsOrdered() ); convertDbArray(cl.line,line); } templateclass Array> inline void LineT::Destroy() { line.Destroy(); } templateclass Array> inline double LineT::Length() const { assert( IsDefined() ); return length; } templateclass Array> inline const Rectangle<2> LineT::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 LineT::IsOrdered() const { return ordered; } templateclass Array> inline bool LineT::IsEmpty() const { return !IsDefined() || (line.Size() == 0); } templateclass Array> inline int LineT::Size() const { return line.Size(); } templateclass Array> inline void LineT::Get( const int i, HalfSegment& hs ) const { assert( IsDefined() ); assert(i>=0); assert(iclass Array> inline void LineT::Resize(const int newSize){ if(newSize>Size()){ line.resize(newSize); } } templateclass Array> inline void LineT::TrimToSize(){ line.TrimToSize(); } templateclass Array> inline void LineT::Put( const int i, const HalfSegment& hs ) { assert( IsDefined() ); line.Put( i, hs ); } templateclass Array> inline void LineT::SelectFirst() const { if( IsEmpty() ) pos = -1; else pos = 0; } templateclass Array> inline void LineT::SelectNext() const { if( pos >= 0 && pos < Size() - 1 ) pos++; else pos = -1; } templateclass Array> inline bool LineT::EndOfHs() const { return pos == -1; } templateclass Array> inline bool LineT::GetHs( HalfSegment& hs ) const { assert( IsDefined() ); if( pos >= 0 && pos <= Size()-1 ) { line.Get( pos, &hs ); return true; } return false; } templateclass Array> template double LineT::Distance( const LineType& l, const Geoid* geoid /* = 0 */ ) const { assert( !IsEmpty() ); // includes !undef assert( !l.IsEmpty() ); // includes !undef assert(!geoid || geoid->IsDefined() ); if( IsEmpty() || l.IsEmpty()){ return -1; } assert( IsOrdered() ); assert( l.IsOrdered() ); HalfSegment hs1, hs2; double result = std::numeric_limits::max(); double segDistance = -666.666; 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( hs1.Intersects( hs2, geoid ) ){ return 0.0; } segDistance = hs1.Distance( hs2, geoid ); if(geoid && AlmostEqual(segDistance,0.0)){ return 0.0; } if(segDistance>=0.0){ result = MIN( result, segDistance ); } } } } return result; } int HalfSegmentCompare(const void *a, const void *b); /* 7 Type Constructor ~line~ A ~line~ value is a set of halfsegments. In the external (nestlist) representation, a line value is expressed as a set of segments. However, in the internal (class) representation, it is expressed as a set of sorted halfsegments, which are stored as a PArray. 7.1 Implementation of the class ~line~ */ templateclass Array> void LineT::StartBulkLoad() { ordered = false; } /* ~EndBulkLoad~ Finishs the bulkload for a line. If this function is called, both HalfSegments assigned to a segment of the line must be part of this line. The parameter ~sort~ can be set to __false__ if the Halfsegments are already ordered using the HalfSegment order. The parameter ~realminize~ can be set to __false__ if the line is already realminized, meaning each pair of different Segments has at most a common endpoint. Furthermore, the two halgsegments belonging to a segment must have the same edge number. The edge numbers mut be in Range [0..Size()-1]. HalfSegments belonging to different segments must have different edge numbers. Only change one of the parameters if you exacly know what you do. Changing such parameters without fulifilling the conditions stated above may construct invalid line representations which again may produce a system crash within some operators. */ templateclass Array> void LineT::EndBulkLoad( const bool sort /* = true */, const bool realminize /* = true */, const bool robust /* = false */ //don't try plane sweep ){ if( !IsDefined() ) { Clear(); SetDefined( false ); } if(sort){ Sort(); } if(Size()>0){ if(realminize){ Array* line2 = ::Realminize(line,false, robust); line2->Sort(HalfSegmentCompare); line.copyFrom(*line2); line2->Destroy(); delete line2; } SetPartnerNo(); } computeComponents(); TrimToSize(); } templateclass Array> templateclass Array2> LineT& LineT::operator=( const LineT& l ) { assert( l.ordered ); convertDbArrays(l.line,line); bbox = l.bbox; length = l.length; noComponents = l.noComponents; ordered = true; currentHS = l.currentHS; this->SetDefined(l.IsDefined()); return *this; } templateclass Array> LineT& LineT::operator=( const LineT& l ) { assert( l.ordered ); line.copyFrom(l.line); bbox = l.bbox; length = l.length; noComponents = l.noComponents; ordered = true; currentHS = l.currentHS; this->SetDefined(l.IsDefined()); return *this; } templateclass Array> bool LineT::operator==( const LineT& l ) const { if(!IsDefined() && !l.IsDefined()){ return true; } if(!IsDefined() || !l.IsDefined()){ return false; } if( IsEmpty() && l.IsEmpty() ) { return true; } if( Size() != l.Size() ){ return false; } if( bbox != l.bbox ){ return false; } assert( ordered && l.ordered ); HalfSegment hs, lhs; for(int i=0;iclass Array> bool LineT::operator!=( const LineT& l ) const { return !( *this == l); } templateclass Array> LineT& LineT::operator+=( const HalfSegment& hs ) { if(!IsDefined()){ assert( IsDefined() ); return *this; } if( IsEmpty() ) bbox = hs.BoundingBox(); else bbox = bbox.Union( hs.BoundingBox() ); if( !IsOrdered() ) line.Append( hs ); else { int pos; if( !Find( hs, pos ) ) { HalfSegment auxhs; for( int i = line.Size() - 1; i >= pos; i++ ) { line.Get( i, auxhs ); line.Put( i+1, auxhs ); } line.Put( pos, hs ); } } return *this; } templateclass Array> LineT& LineT::operator+=(const LineT& l){ if(!IsDefined() || !l.IsDefined()){ SetDefined( false ); return *this; } if(l.line.Size()==0){ return *this; } assert(!IsOrdered()); if(IsEmpty()){ bbox = l.bbox; } else { bbox = bbox.Union(l.bbox); } line.Append(l.line); return *this; } templateclass Array> LineT& LineT::operator-=( const HalfSegment& hs ) { if(!IsDefined()){ return *this; } assert( IsOrdered() ); int pos; HalfSegment auxhs; if( Find( hs, pos ) ) { for( int i = pos; i < Size(); i++ ) { line.Get( i+1, auxhs ); line.Put( i, auxhs ); } } // Naive way to redo the bounding box. if( IsEmpty() ) bbox.SetDefined( false ); int i = 0; line.Get( i++, auxhs ); bbox = auxhs.BoundingBox(); for( ; i < Size(); i++ ) { line.Get( i, auxhs ); bbox = bbox.Union( auxhs.BoundingBox() ); } return *this; } templateclass Array> bool LineT::Contains( const Point& p, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( p.IsDefined() ); if( IsEmpty() || (geoid&& !geoid->IsDefined())) return false; int pos; if( Find( p, pos ) ) return true; if( pos >= Size() ) return false; HalfSegment hs; for( ; pos >= 0; pos-- ){ Get( pos, hs ); if( hs.IsLeftDomPoint() ){ if( hs.Contains( p ) ) return true; } } return false; } templateclass Array> templateclass Array2> bool LineT::Intersects( const LineT& l, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( l.IsDefined() ); if( IsEmpty() || l.IsEmpty() ) return false; assert( IsOrdered() ); assert( l.IsOrdered() ); if( !BoundingBox().Intersects( l.BoundingBox() ) ) return false; HalfSegment hs1, hs2; 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.Intersects( hs2 ) ) return true; } } } } return false; } templateclass Array> templateclass Array2> bool LineT::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() ); HalfSegment hsl, hsr; for( int i = 0; i < Size(); i++ ){ Get( i, hsl ); if( hsl.IsLeftDomPoint() ){ for( int j = 0; j < r.Size(); j++ ){ r.Get( j, hsr ); if( hsr.IsLeftDomPoint() ){ if( hsl.Intersects( hsr,geoid ) ) return true; } } if( r.Contains( hsl.GetLeftPoint(),geoid ) || r.Contains( hsl.GetRightPoint(),geoid ) ){ return true; } } } return false; } templateclass Array> templateclass Array2> bool LineT::Inside( const LineT& l, const Geoid* geoid/*=0*/ ) const { assert( IsDefined() ); assert( l.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(!IsDefined() || !l.IsDefined() || (geoid && !geoid->IsDefined()) ){ return false; } if( IsEmpty() ){ return true; } if( l.IsEmpty() ){ return false; } if( !l.BoundingBox().Contains( bbox ) ){ return false; } assert( IsOrdered() ); assert( l.IsOrdered() ); HalfSegment hs1, hs2; for( int i = 0; i < Size(); i++ ){ Get( i, hs1 ); if( hs1.IsLeftDomPoint() ){ bool found = false; for( int j = 0; j < l.Size() && !found; j++ ){ l.Get( j, hs2 ); if( hs2.IsLeftDomPoint() && hs1.Inside( hs2,geoid ) ){ found = true; } } if( !found ){ return false; } } } return true; } templateclass Array> templateclass Array2> bool LineT::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; } if( !r.BoundingBox().Contains( bbox ) ){ return false; } assert( IsOrdered() ); assert( r.IsOrdered() ); HalfSegment hsl; for( int i = 0; i < Size(); i++ ){ Get( i, hsl ); if( hsl.IsLeftDomPoint() ){ if( !r.Contains( hsl ) ){ return false; } } } return true; } templateclass Array> templateclass Array2> bool LineT::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() ) ){ return false; } assert( IsOrdered() ); assert( r.IsOrdered() ); HalfSegment hsl, hsr; bool found = false; for( int i = 0; i < Size(); i++ ){ Get( i, hsl ); if( hsl.IsLeftDomPoint() ){ if( r.InnerContains( hsl.GetLeftPoint(),geoid ) || r.InnerContains( hsl.GetRightPoint(),geoid ) ){ return false; } for( int j = 0; j < r.Size(); j++ ){ r.Get( j, hsr ); if( hsr.IsLeftDomPoint() ) { if( !hsr.Intersects( hsl,geoid ) ){ continue; } found = true; if( hsr.Crosses( hsl,geoid ) ){ return false; } } } } } return found; } templateclass Array> templateclass Array2> void LineT::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 LineT::Intersection(const PointsT& ps, PointsT& result, const Geoid* geoid/*=0*/) const{ // naive implementation, should be changed to be faster 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 LineT::Intersection( const LineT& l, LineT& result, const Geoid* geoid/*=0*/ ) const { SetOp(*this,l,result,avlseg::intersection_op, geoid); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Intersection(const RegionT& r, LineT& result, const Geoid* geoid/*=0*/) const{ r.Intersection(*this,result,geoid); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Intersection( const SimpleLineT& l, SimpleLineT& result, const Geoid* geoid/*=0*/ ) const { SetOp(*this,l,result,avlseg::intersection_op, geoid); } templateclass Array> templateclass Array2> void LineT::Minus(const Point& p, LineT& result, const Geoid* geoid/*=0*/) const { result.Clear(); if(!IsDefined() || !p.IsDefined()){ result.SetDefined(false); return; } result.CopyFrom(this); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Minus(const PointsT& ps, LineT& result, const Geoid* geoid/*=0*/) const { result.Clear(); if(!IsDefined() || !ps.IsDefined() || (geoid&& !geoid->IsDefined()) ){ result.SetDefined(false); return; } result.CopyFrom(this); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Minus(const LineT& line, LineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,line,result,avlseg::difference_op,geoid); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Minus(const RegionT& region, LineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,region, result,avlseg::difference_op,geoid); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Minus(const SimpleLineT& line, LineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,line,result,avlseg::difference_op,geoid); } templateclass Array> templateclass Array2> void LineT::Union(const Point& p, LineT& result, const Geoid* geoid/*=0*/) const{ result.Clear(); if(!IsDefined() || !p.IsDefined() || (geoid&& !geoid->IsDefined()) ){ result.SetDefined(false); return; } result.CopyFrom(this); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Union(const PointsT& ps, LineT& result, const Geoid* geoid/*=0*/) const{ result.Clear(); if(!IsDefined() || !ps.IsDefined() || (geoid&& !geoid->IsDefined())){ result.SetDefined(false); return; } result.CopyFrom(this); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Union(const LineT& line, LineT& result, const Geoid* geoid/*=0*/) const{ try{ SetOp(*this, line, result, avlseg::union_op,geoid,true); } catch(...){ std::cerr << "union via plane sweep failed, use slower implementation"; result.Clear(); result.Resize(this->Size()+line.Size()); HalfSegment hs; result.StartBulkLoad(); for(int i=0;iSize();i++){ this->Get(i,hs); result += hs; } result.EndBulkLoad(true,true,true); } } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Union(const RegionT& region, RegionT& result, const Geoid* geoid/*=0*/) const{ region.Union(*this,result,geoid); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Union(const SimpleLineT& line, LineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this, line, result, avlseg::union_op,geoid); } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Crossings( 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() ); assert( 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(true, true); // sort and remove duplicates } templateclass Array> templateclass Array2> void LineT::Crossings(PointsT& result, const Geoid* geoid/*=0*/) const{ result.Clear(); if(!IsDefined() || (geoid&& !geoid->IsDefined())){ result.SetDefined(false); return; } result.SetDefined(true); int i = 0; int size = Size(); Point lastPoint(false); HalfSegment hs; Point p(true); int count = 0; result.StartBulkLoad(); while(i2){ // crossing found result += p; } lastPoint = p; count = 1; } } if(lastPoint.IsDefined() && count>2){ result += lastPoint; } result.EndBulkLoad(); } templateclass Array> double LineT::Distance( const Point& p, const Geoid* geoid /* = 0 */ ) const { assert( !IsEmpty() ); assert( p.IsDefined() ); assert(!geoid || geoid->IsDefined() ); if( IsEmpty() || !p.IsDefined()){ return -1; } assert( IsOrdered() ); HalfSegment hs; double result = std::numeric_limits::max(); double segDistance = -666.666; for( int i = 0; i < Size(); i++ ){ Get( i, hs ); if( hs.IsLeftDomPoint() ){ if( !geoid && hs.Contains( p ) ){ return 0.0; } segDistance = hs.Distance( p, geoid ); if(geoid && AlmostEqual(segDistance,0.0)){ return 0.0; } if(segDistance>=0.0){ result = MIN( result, segDistance ); } } } return result; } templateclass Array> double LineT::MaxDistance( const Point& p, const Geoid* geoid /* = 0 */ ) const { assert( !IsEmpty() ); assert( p.IsDefined() ); assert(!geoid || geoid->IsDefined() ); if( IsEmpty() || !p.IsDefined()){ return -1; } assert( IsOrdered() ); HalfSegment hs; double result = 0; double segDistance = -666.666; for( int i = 0; i < Size(); i++ ){ Get( i, hs ); if( hs.IsLeftDomPoint() ) { segDistance = hs.Distance( p, geoid ); if(segDistance>=0.0){ result = MAX( result, segDistance ); } } } return result; } templateclass Array> templateclass Array2> double LineT::Distance( const PointsT& ps, const Geoid* geoid /* = 0 */ ) const { assert( !IsEmpty() ); // includes !undef assert( !ps.IsEmpty() ); // includes !undef assert(!geoid || geoid->IsDefined() ); if( IsEmpty() || ps.IsEmpty()){ return -1; } assert( IsOrdered() ); assert( ps.IsOrdered() ); HalfSegment hs; Point p(true); double result = std::numeric_limits::max(); double segDistance = -666.666; for( int i = 0; i < Size(); i++ ){ Get( i, hs ); if( hs.IsLeftDomPoint() ){ for( int j = 0; j < ps.Size(); j++ ){ ps.Get( j, p ); if(!geoid && hs.Contains( p, geoid ) ){ return 0.0; } segDistance = hs.Distance( p, geoid ); if(geoid && AlmostEqual(segDistance,0.0)){ return 0.0; } if(segDistance>=0.0){ result = MIN( result, segDistance ); } } } } return result; } templateclass Array> templateclass Array2> void LineT::DistanceSmallerThan(const LineT& l, const double maxDist, const bool allowEqual, CcBool& result, const Geoid* geoid) const{ assert( !IsEmpty() ); // includes !undef assert( !l.IsEmpty() ); // includes !undef assert(!geoid || geoid->IsDefined() ); if( IsEmpty() || l.IsEmpty()){ result.SetDefined(false); return; } assert( IsOrdered() ); assert( l.IsOrdered() ); if(maxDist < 0 || (AlmostEqual(maxDist,0) && !allowEqual)){ result.SetDefined(false); return; } HalfSegment hs1, hs2; double segDistance = -666.666; 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( hs1.Intersects( hs2, geoid ) ){ result.Set(true,true); return; } segDistance = hs1.Distance( hs2, geoid ); if( (segDistance < maxDist) || (allowEqual && AlmostEqual(segDistance,maxDist))){ result.Set(true,true); return; } } } } result.Set(true,false); } templateclass Array> double LineT::Distance( const Rectangle<2>& r, const Geoid* geoid /*=0*/ ) const { assert( !IsEmpty() ); // includes !undef assert( IsOrdered() ); assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." <IsDefined()) ){ return -1; } assert( IsOrdered() ); HalfSegment hs; double dist = std::numeric_limits::max(); for(int i=0; i < line.Size() && dist>0; i++){ line.Get(i,hs); if(hs.IsLeftDomPoint()){ double d = hs.Distance(r,geoid); if(dclass Array> bool LineT::Intersects( const Rectangle<2>& r, const Geoid* geoid /*=0*/ ) const { assert( !IsEmpty() ); // includes !undef assert( IsOrdered() ); assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(!BoundingBox().Intersects(r,geoid)){ return false; } if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." <class Array> double LineT::MaxDistance( const Rectangle<2>& r, const Geoid* geoid /*=0*/ ) const { assert( !IsEmpty() ); // includes !undef assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." < dist){ dist = d; } } } return dist; } templateclass Array> int LineT::NoComponents() const { return noComponents; } templateclass Array> templateclass Array2> void LineT::Translate( const Coord& x, const Coord& y, LineT& result ) const { result.Clear(); if(!IsDefined()){ result.SetDefined(false); return; } result.SetDefined(true); assert( IsOrdered() ); result.Resize(this->Size()); result.bbox = this->bbox; HalfSegment hs; for( int i = 0; i < Size(); i++ ) { Get( i, hs ); hs.Translate( x, y ); result.line.Put(i,hs); } double t[2] = {x, y}; result.bbox.Translate(t); } templateclass Array> templateclass Array2> void LineT::Rotate( const Coord& x, const Coord& y, const double alpha, LineT& 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); for( int i = 0; i < Size(); i++ ) { Get( i, hso ); p1.Set( m00*hso.GetLeftPoint().GetX() + m01*hso.GetLeftPoint().GetY() + m02, m10*hso.GetLeftPoint().GetX() + m11*hso.GetLeftPoint().GetY() + m12); p2.Set( m00*hso.GetRightPoint().GetX() + m01*hso.GetRightPoint().GetY() + m02, m10*hso.GetRightPoint().GetX() + m11*hso.GetRightPoint().GetY() + m12); HalfSegment hsr(hso); // ensure to copy attr; hsr.Set(hso.IsLeftDomPoint(),p1,p2); result += hsr; } result.EndBulkLoad(); // reordering may be required } templateclass Array> templateclass Array2> void LineT::Scale( const Coord& sx, const Coord& sy, LineT& 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 += hso; } } result.EndBulkLoad(); // reordering may be required } templateclass Array> templateclass Array2> void LineT::Transform( RegionT& result ) const { result.Clear(); if( !IsDefined() ){ result.SetDefined( false ); return; } result.SetDefined( true ); if(Size()==0){ return; } char* usage = new char[Size()]; char* critical = new char[this->Size()]; markUsage(&(this->line), usage, critical); Array* halfsegments = new Array(this->Size()); if( !IsEmpty() ) { assert( IsOrdered() ); HalfSegment hs; int edgeno=0; for( int i = 0; i < Size(); i++ ) { if(usage[i] != 1){ assert(usage[i]!=3); Get( i, hs ); if(hs.IsLeftDomPoint()){ hs.attr.edgeno = edgeno; halfsegments->Append(hs); hs.SetLeftDomPoint(false); halfsegments->Append(hs); edgeno++; } } } } halfsegments->Sort(HalfSegmentCompare); RegionCreator::setPartnerNo(halfsegments); RegionCreator::createRegion(halfsegments,&result); halfsegments->destroyIfNonPersistent(); delete halfsegments; delete[] usage; delete[] critical; } templateclass Array> void LineT::Realminize(){ // special case: empty line if(!IsDefined()){ line.clean(); return; } LineT tmp(0); Realminize2(*this,tmp); *this = tmp; } templateclass Array> templateclass Array2> void LineT::Boundary(PointsT* result) const{ // we assume that the interior of each halfsegment has no // common point with any part of another halfsegment result->Clear(); if(!IsDefined()){ result->SetDefined(false); return; } result->SetDefined(true); if(IsEmpty()){ return; } HalfSegment hs; HalfSegment hs_n; // neighbooring halfsegment Point p(true); int size = Size(); result->StartBulkLoad(); for(int i=0;i0){ Get(i-1,hs_n); if(p==hs_n.GetDomPoint()){ common=true; } } if(iEndBulkLoad(false,false); } templateclass Array> bool LineT::Find( const HalfSegment& hs, int& pos, const bool& exact ) const { assert( IsDefined() ); assert( IsOrdered() ); if( exact ) return line.Find( &hs, HalfSegmentCompare, pos ); return line.Find( &hs, HalfSegmentCompare, pos ); } templateclass Array> bool LineT::Find( const Point& p, int& pos, const bool& exact ) const { assert( IsDefined() ); assert( p.IsDefined() ); assert( IsOrdered() ); if( exact ) return line.Find( &p, PointHalfSegmentCompare, pos ); return line.Find( &p, PointHalfSegmentCompareAlmost, pos ); } templateclass Array> void LineT::SetPartnerNo() { if(!IsDefined() || line.Size()==0){ return; } // reserve a slot for each edgeno int tmpsize = (line.Size()+1)/2; DbArray TMP(tmpsize); // intialize the array (it's only needed for // wrong sorted halfsegments) for(int i=0;i=0){ // error case, segment already registered std::cerr << "wrong order in halfsegment array" << std::endl; std::cerr << "the system may be instable" << std::endl; int leftpos = lpp; HalfSegment right = hs1; right.attr.partnerno = leftpos; right.attr.insideAbove = false; right.attr.coverageno = 0; right.attr.cycleno = 0; right.attr.faceno = 0; line.Get(leftpos,hs2); HalfSegment left = hs2; left.attr.partnerno = i; left.attr.insideAbove = false; left.attr.coverageno = 0; left.attr.cycleno = 0; left.attr.faceno = 0; line.Put(i,right); line.Put(leftpos,left); } else { // normal case, put number to tmp TMP.Put(hs1.attr.edgeno, i); } } else { // RightDomPoint if(lpp<0){ // error case left segment not found std::cerr << "Error in halfsegment array detected" << std::endl; std::cerr << "may be a wrong ordering or wrong set edgeno's" << std::endl; TMP.Put(hs1.attr.edgeno, i); } else { int leftpos = lpp; HalfSegment right = hs1; right.attr.partnerno = leftpos; right.attr.insideAbove = false; right.attr.coverageno = 0; right.attr.cycleno = 0; right.attr.faceno = 0; line.Get(leftpos,hs2); HalfSegment left = hs2; left.attr.partnerno = i; left.attr.insideAbove = false; left.attr.coverageno = 0; left.attr.cycleno = 0; left.attr.faceno = 0; line.Put(i,right); line.Put(leftpos,left); } } } TMP.Destroy(); } templateclass Array> bool LineT::GetNextSegment( const int poshs, const HalfSegment& hs, int& posnexths, HalfSegment& nexths ) { if( poshs > 0 ) { Get( posnexths = poshs - 1, nexths ); if( hs.GetDomPoint() == nexths.GetDomPoint() ) return true; } if( poshs < Size() - 1 ) { Get( posnexths = poshs + 1, nexths ); if( hs.GetDomPoint() == nexths.GetDomPoint() ) return true; } return false; } templateclass Array> bool LineT::GetNextSegments( const int poshs, const HalfSegment& hs, std::vector& visited, int& posnexths, HalfSegment& nexths, std::stack< std::pair >& nexthss) { bool first = true; HalfSegment aux; int auxposhs = poshs; while( auxposhs > 0 ) { auxposhs--; if( !visited[auxposhs] ) { Get( auxposhs, aux ); if( hs.GetDomPoint() == aux.GetDomPoint() ) { if( first ) { first = false; nexths = aux; posnexths = auxposhs; } else nexthss.push( std::make_pair( auxposhs, aux ) ); } else break; } } auxposhs = poshs; while( auxposhs < Size() - 1 ) { auxposhs++; if( !visited[auxposhs] ) { Get( auxposhs, aux ); if( hs.GetDomPoint() == aux.GetDomPoint() ) { if( first ) { first = false; nexths = aux; posnexths = auxposhs; } else nexthss.push( std::make_pair( auxposhs, aux ) ); } else break; } } return !first; } /* ~computeComponents~ Computes FaceNo, edgeno of each halfsegment. Sets length,noComponents, and bbox of the line. */ templateclass Array> int LineT::getUnusedExtension(int startPos,const Array& used)const{ HalfSegment hs; line.Get(startPos,hs); Point p = hs.GetDomPoint(); int pos = startPos-1; bool done = false; bool u; // search on the left side while(pos>=0 && !done){ line.Get(pos,hs); Point p2 = hs.GetDomPoint(); if(!AlmostEqual(p,p2)){ done = true; }else { used.Get(pos,u); if(!u){ return pos; } else { pos--; } } } // search on the right side done = false; pos = startPos+1; int size = line.Size(); while(!done && posclass Array> void LineT::collectFace(int faceno, int startPos, Array& used){ std::set extensionPos; used.Put(startPos,true); HalfSegment hs1; HalfSegment hs2; int pos = startPos; line.Get(startPos,hs1); HalfSegment Hs1 = hs1; int edgeno = 0; Hs1.attr.insideAbove=false; Hs1.attr.coverageno = 0; Hs1.attr.cycleno=0; Hs1.attr.faceno=faceno; Hs1.attr.edgeno = edgeno; line.Put(pos,Hs1); used.Put(pos,true); // get and Set the Partner int partner = Hs1.attr.partnerno; line.Get(partner,hs2); HalfSegment Hs2 = hs2; Hs2.attr.insideAbove=false; Hs2.attr.coverageno = 0; Hs2.attr.cycleno=0; Hs2.attr.faceno=faceno; Hs2.attr.edgeno = edgeno; used.Put(partner,true); line.Put(partner,Hs2); if(!bbox.IsDefined()){ bbox = hs1.BoundingBox(); } else { bbox = bbox.Union(hs1.BoundingBox()); } length += hs1.Length(); if(getUnusedExtension(pos,used)>=0){ extensionPos.insert(pos); } if(getUnusedExtension(partner,used)>=0){ extensionPos.insert(partner); } edgeno++; while(!extensionPos.empty()){ int spos = *(extensionPos.begin()); pos = getUnusedExtension(spos,used); if(pos < 0){ extensionPos.erase(spos); } else { // extension found at position pos line.Get(pos,hs1); Hs1 = (hs1); Hs1.attr.insideAbove=false; Hs1.attr.coverageno = 0; Hs1.attr.cycleno=0; Hs1.attr.faceno=faceno; Hs1.attr.edgeno = edgeno; used.Put(pos,true); line.Put(pos,Hs1); partner = Hs1.attr.partnerno; line.Get(partner,hs2); Hs2 = (hs2); Hs2.attr.insideAbove=false; Hs2.attr.coverageno = 0; Hs2.attr.cycleno=0; Hs2.attr.faceno=faceno; Hs2.attr.edgeno = edgeno; used.Put(partner,true); line.Put(partner,Hs2); if(getUnusedExtension(partner,used)>=0){ extensionPos.insert(partner); } length += hs1.Length(); bbox = bbox.Union(hs1.BoundingBox()); edgeno++; } } } /* ~ComputeComponents~ Computes the length of this lines as well as its bounding box and the number of components of this line. Each Halfsegment is assigned to a face number (the component) and an egde number within this face. */ templateclass Array> void LineT::computeComponents() { length = 0.0; noComponents = 0; bbox.SetDefined(false); if(!IsDefined() || Size()==0){ return; } Array used(line.Size()); for(int i=0;iclass Array> void LineT::Sort() { assert( !IsOrdered() ); line.Sort( HalfSegmentCompare ); ordered = true; } templateclass Array> void LineT::RemoveDuplicates() { assert( IsOrdered() ); int size = line.Size(); if( size == 0 ){ // nothing to do return; } int newEdgeNumbers[size]; // mapping oldnumber -> newnumber for(int i=0;iclass Array> templateclass Array2> void LineT::WindowClippingIn( const Rectangle<2> &window, LineT &clippedLine, bool &inside ) const { clippedLine.Clear(); if( !IsDefined() || !window.IsDefined() ) { clippedLine.SetDefined( false ); return; } clippedLine.SetDefined( true ); inside = false; clippedLine.StartBulkLoad(); for (int i=0; i < Size();i++) { HalfSegment hs; HalfSegment hsInside; bool insidehs = false, isIntersectionPoint = false; Get( i, hs ); if( hs.IsLeftDomPoint() ) { Point intersectionPoint(true); hs.WindowClippingIn( window, hsInside, insidehs, isIntersectionPoint, intersectionPoint ); if( insidehs && !isIntersectionPoint ) { clippedLine += hsInside; hsInside.SetLeftDomPoint( !hsInside.IsLeftDomPoint() ); clippedLine += hsInside; inside = true; } } } clippedLine.EndBulkLoad(); } templateclass Array> templateclass Array2> void LineT::WindowClippingOut( const Rectangle<2> &window, LineT &clippedLine, bool &outside ) const { clippedLine.Clear(); if( !IsDefined() || !window.IsDefined() ) { clippedLine.SetDefined( false ); return; } clippedLine.SetDefined( true ); outside = false; clippedLine.StartBulkLoad(); for (int i=0; i < Size();i++) { HalfSegment hs; HalfSegment hsInside; bool outsidehs = false, isIntersectionPoint = false; Get( i, hs ); if( hs.IsLeftDomPoint() ) { Point intersectionPoint(true); hs.WindowClippingIn( window, hsInside, outsidehs, isIntersectionPoint, intersectionPoint ); if( outsidehs && !isIntersectionPoint ) { 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. HalfSegment hsLeft( true, hs.GetLeftPoint(), hsInside.GetLeftPoint() ); AttrType attr = hs.GetAttr(); hsLeft.SetAttr(attr); clippedLine += hsLeft; hsLeft.SetLeftDomPoint( !hsLeft.IsLeftDomPoint() ); clippedLine += hsLeft; outside = true; } if( hs.GetRightPoint() != hsInside.GetRightPoint() ) {//Add the part of the half segment composed by the left // point of hs and the left point of hsInside. HalfSegment hsRight( true, hs.GetRightPoint(), hsInside.GetRightPoint() ); AttrType attr=hs.GetAttr(); hsRight.SetAttr(attr); clippedLine += hsRight; hsRight.SetLeftDomPoint( !hsRight.IsLeftDomPoint() ); clippedLine += hsRight; outside = true; } } else { HalfSegment auxhs = hs; clippedLine += auxhs; auxhs.SetLeftDomPoint( !auxhs.IsLeftDomPoint() ); clippedLine += auxhs; outside = true; } } } clippedLine.EndBulkLoad(); } templateclass Array> std::ostream& operator<<( std::ostream& os, const LineT& cl ) { os << "<"; if( !cl.IsDefined() ) { os << " undefined "; } else { HalfSegment hs; for( int i = 0; i < cl.Size(); i++ ) { cl.Get( i, hs ); os << " " << hs << endl; } } os << ">"; return os; } templateclass Array> size_t LineT::HashValue() const { if( IsEmpty() ) // subsumes undef return 0; size_t h = 0; HalfSegment hs; Coord x1, y1, x2, y2; for( int i = 0; i < Size() && i < 5; i++ ) { Get( i, hs ); x1 = hs.GetLeftPoint().GetX(); y1 = hs.GetLeftPoint().GetY(); x2 = hs.GetRightPoint().GetX(); y2 = hs.GetRightPoint().GetY(); h += (size_t)( (5 * x1 + y1) + (5 * x2 + y2) ); } return h; } templateclass Array> void LineT::Clear() { line.clean(); pos = -1; ordered = true; bbox.SetDefined( false ); SetDefined(true); } templateclass Array> void LineT::CopyFrom( const Attribute* right ) { *this = *((const LineT *)right); } templateclass Array> templateclass Array2> void LineT::CopyFrom( const LineT* right ) { *this = *right; } templateclass Array> int LineT::Compare( const Attribute *arg ) const { return Compare( *(LineT*) arg); } templateclass Array> templateclass Array2> int LineT::Compare( const LineT& l ) const { if(!IsDefined() && !l.IsDefined()){ return 0; } if(!IsDefined()){ return -1; } if(!l.IsDefined()){ return 1; } if( Size() > l.Size() ) return 1; if( Size() < l.Size() ) return -1; if(Size()==0){ return 0; } object obj; status stat; SelectFirst_ll( *this, l, obj, stat ); while( stat == endnone ) { if( obj == first ) return -1; if( obj == second ) return 1; SelectNext_ll( *this, l, obj, stat ); } return 0; } templateclass Array> LineT* LineT::Clone() const { return new LineT( *this ); } templateclass Array> double LineT::Length(const Geoid &geoid, bool& valid) const { valid = true; if(!IsDefined()){ valid = false; return 0.0; } double length = 0.0; for (int i=0; (valid && (iclass Array> std::ostream& LineT::Print( std::ostream &os ) const { std::ios_base::fmtflags oldOptions = os.flags(); os.setf(std::ios_base::fixed,std::ios_base::floatfield); os.precision(8); os << "<"; if( !IsDefined() ) { os << " undefined "; } else { HalfSegment hs; for( int i = 0; i < Size(); i++ ) { Get( i, hs ); os << " " << hs << endl; } } os << ">"; os.flags(oldOptions); return os; } templateclass Array> templateclass Array2, templateclass Array3> void LineT::Simplify(LineT& result, const double epsilon, const PointsT& importantPoints /*= Points(0)*/ , const Geoid* geoid /*= 0*/) const{ result.Clear(); // remove old stuff if( !IsDefined() || (geoid && !geoid->IsDefined()) ){ // this/geoid undefined result.SetDefined(false); return; } result.SetDefined(true); if(epsilon<=0){ // maximum derivation reached in each case result.CopyFrom(this); return; } // at least one immediate point is required to simplify // the line, thus at leat 4 halfsegments are needed. if(Size()<4){ result.CopyFrom(this); return; } // an array with the used halfsegments bool used[Size()]; for(int i=0;i forward; std::vector backward; std::vector complete; HalfSegment hs; // current halfsegment result.StartBulkLoad(); int pos = 0; int size = Size(); int egdeno=0; while(pos=0; i--){ complete.push_back(backward[i]); } for(unsigned int i=0;iclass Array> templateclass Array2> void LineT::Vertices( PointsT* result ) const { result->Clear(); if(!IsDefined()){ result->SetDefined(false); return; } result->SetDefined(true); if( IsEmpty() ){ return; } assert( IsOrdered() ); HalfSegment hs; result->StartBulkLoad(); for( int i = 0; i < Size(); i++ ) { Get( i, hs ); *result += hs.GetDomPoint(); } result->EndBulkLoad( false, true ); } #endif