/* ---- 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 "SimpleLineT.h" #include "LineT.h" #include "AVLSegment.h" #include "../../Tools/Flob/MMDbArray.h" #include "SpatialAlgebra.h" /* 7 The type SimpleLineT 7.1 Constructor This constructor coinstructs a simple line from ~src~ If ~src~ is not simple, the simple line will be invalidated, i.e. the defined flag is set to false; */ template class Array> template class Array2> SimpleLineT::SimpleLineT(const LineT& src): StandardSpatialAttribute<2>(src.IsDefined()), segments(0),lrsArray(0), startSmaller(true), isCycle(false),isOrdered(true),length(0.0), bbox(false),currentHS(-1) { fromLine(src); } /* 7.2 Bulk Loading Functions */ template class Array> void SimpleLineT::StartBulkLoad(){ isOrdered = false; SetDefined( true ); } /* ~Operator +=~ Appends an HalfSegment during BulkLoading. */ template class Array> SimpleLineT& SimpleLineT::operator+=(const HalfSegment& hs){ assert(!isOrdered && IsDefined()); segments.Append(hs); return *this; } template class Array> void SimpleLineT::Add(const HalfSegment& hs) { assert(!isOrdered && IsDefined()); segments.Append(hs); } template class Array> bool SimpleLineT::EndBulkLoad(){ if( !IsDefined() ) { Clear(); SetDefined( false ); } // Sort the segments Sort(); // Realminize the segments Array* tmp; tmp = Realminize(segments); segments.clean(); segments.copyFrom(*tmp); tmp->Destroy(); delete tmp; SetPartnerNo(); // recompute Bounding box; if(segments.Size()>0){ HalfSegment hs; segments.Get(0,hs); bbox = hs.BoundingBox(); for(int i=1; i< segments.Size();i++){ segments.Get(i,hs); bbox = bbox.Union(hs.BoundingBox()); } }else{ bbox.SetDefined(false); } if(!computePolyline()){ Clear(); SetDefined(false); return false; } else { TrimToSize(); return true; } } /* ~StartPoint~ Determines the startPoint of this simple line. */ template class Array> Point SimpleLineT::StartPoint() const { if( !IsDefined() || IsEmpty() ) return Point( false ); LRS lrs; HalfSegment hs; int pos = 0; if (startSmaller){ lrsArray.Get( pos, lrs ); // Get half-segment segments.Get( lrs.hsPos, hs ); // Return one end of the half-segment depending // on the start. return hs.GetDomPoint(); } else { pos = lrsArray.Size()-1; lrsArray.Get( pos, lrs ); // Get half-segment segments.Get( lrs.hsPos, hs ); // Return one end of the half-segment depending // on the start. return hs.GetSecPoint(); } } template class Array> Point SimpleLineT::StartPoint( bool startsSmaller ) const { if( IsEmpty() || !IsDefined() ) return Point( false ); if (startsSmaller == startSmaller) return StartPoint(); else return EndPoint(); } /* ~EndPoint~ Returns the endpoint of this simple Line. */ template class Array> Point SimpleLineT::EndPoint() const { if( !IsDefined() || IsEmpty()) return Point( false ); LRS lrs; HalfSegment hs; int pos = lrsArray.Size()-1; if (startSmaller){ lrsArray.Get( pos, lrs ); // Get half-segment segments.Get( lrs.hsPos, hs ); // Return one end of the half-segment depending // on the start. return hs.GetSecPoint(); } else { pos = 0; lrsArray.Get( pos, lrs ); // Get half-segment segments.Get( lrs.hsPos, hs ); // Return one end of the half-segment depending // on the start. return hs.GetDomPoint(); } } template class Array> Point SimpleLineT::EndPoint( bool startsSmaller ) const { if( IsEmpty() || !IsDefined() ) return Point( false ); if (startsSmaller == startSmaller) return EndPoint(); else return StartPoint(); } template class Array> bool SimpleLineT::Contains( const Point& p, const Geoid* geoid /*=0*/ ) const { assert( IsDefined() ); assert( p.IsDefined() ); if( IsEmpty() || !p.IsDefined() || (geoid && !geoid->IsDefined()) ){ return false; } int pos; if( segments.Find( &p, PointHalfSegmentCompareAlmost, pos )){ // p is a dominating point of a line return true; } if( pos >= Size() ){ return false; } HalfSegment hs; for( ; pos >= 0; pos-- ){ segments.Get( pos, &hs ); if( hs.IsLeftDomPoint() ) { if( hs.Contains( p, geoid ) ){ return true; } } } return false; } template class Array> template class Array2> bool SimpleLineT::Inside(const SimpleLineT & l, const Geoid* geoid) 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; } template class Array> template class Array2> void SimpleLineT::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; } } template class Array> template class Array2, template class Array3> void SimpleLineT::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; result.StartBulkLoad(); for(int i=0;iContains(p,geoid)){ result += p; } } result.EndBulkLoad(false,false,false); } template class Array> template class Array2, template class Array3> void SimpleLineT::Intersection( const LineT& l, SimpleLineT& result, const Geoid* geoid/*=0*/ ) const { SetOp(*this,l,result,avlseg::intersection_op, geoid); } template class Array> template class Array2, template class Array3> void SimpleLineT::Intersection( const SimpleLineT& l, SimpleLineT& result, const Geoid* geoid/*=0*/ ) const { SetOp(*this,l,result,avlseg::intersection_op, geoid); } template class Array> template class Array2, template class Array3> void SimpleLineT::Intersection(const RegionT& r, SimpleLineT& result, const Geoid* geoid/*=0*/) const{ r.Intersection(*this,result,geoid); } template class Array> template class Array2> void SimpleLineT::Minus(const Point& p, SimpleLineT& result, const Geoid* geoid/*=0*/) const { result.Clear(); if(!IsDefined() || !p.IsDefined()){ result.SetDefined(false); return; } result.CopyFrom(this); } template class Array> template class Array2, template class Array3> void SimpleLineT::Minus(const PointsT& ps, SimpleLineT& result, const Geoid* geoid/*=0*/) const { result.Clear(); if(!IsDefined() || !ps.IsDefined() || (geoid&& !geoid->IsDefined()) ){ result.SetDefined(false); return; } result.CopyFrom(this); } template class Array> template class Array2, template class Array3> void SimpleLineT::Minus(const LineT& line, SimpleLineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,line,result,avlseg::difference_op,geoid); } template class Array> template class Array2, template class Array3> void SimpleLineT::Minus(const RegionT& region, SimpleLineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,region, result,avlseg::difference_op,geoid); } template class Array> template class Array2, template class Array3> void SimpleLineT::Minus(const SimpleLineT& line, SimpleLineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this,line,result,avlseg::difference_op,geoid); } template class Array> template class Array2> void SimpleLineT::Union(const Point& p, SimpleLineT& result, const Geoid* geoid/*=0*/) const{ result.Clear(); if(!IsDefined() || !p.IsDefined() || (geoid&& !geoid->IsDefined()) ){ result.SetDefined(false); return; } result.CopyFrom(this); } template class Array> template class Array2, template class Array3> void SimpleLineT::Union(const PointsT& ps, SimpleLineT& result, const Geoid* geoid/*=0*/) const{ result.Clear(); if(!IsDefined() || !ps.IsDefined() || (geoid&& !geoid->IsDefined())){ result.SetDefined(false); return; } result.CopyFrom(this); } template class Array> template class Array2, template class Array3> void SimpleLineT::Union(const LineT& line, LineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this, line, result, avlseg::union_op,geoid); } template class Array> template class Array2, template class Array3> void SimpleLineT::Union(const RegionT& region, RegionT& result, const Geoid* geoid/*=0*/) const{ region.Union(*this,result,geoid); } template class Array> template class Array2, template class Array3> void SimpleLineT::Union(const SimpleLineT& line, LineT& result, const Geoid* geoid/*=0*/) const{ SetOp(*this, line, result, avlseg::union_op,geoid); } template class Array> double SimpleLineT::Distance(const Point& p, const Geoid* geoid /* = 0 */)const { assert( !IsEmpty() ); assert( p.IsDefined() ); assert( ! geoid || geoid->IsDefined() ); HalfSegment hs; double result = std::numeric_limits::max(); for( int i = 0; i < Size(); i++ ) { Get( i, hs ); if( hs.IsLeftDomPoint() ) { if( hs.Contains( p ), geoid ){ return 0.0; } result = MIN( result, hs.Distance( p, geoid ) ); } } return result; } template class Array> template class Array2> double SimpleLineT::Distance(const PointsT& ps, const Geoid* geoid /* =0 */)const{ assert( !IsEmpty() ); assert( !ps.IsEmpty() ); assert( ! geoid || geoid->IsDefined() ); HalfSegment hs; Point p; double result = std::numeric_limits::max(); 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( hs.Contains( p, geoid ) ){ return 0; } result = MIN( result, hs.Distance( p, geoid ) ); } } } return result; } template class Array> template class Array2> double SimpleLineT::Distance(const SimpleLineT& sl, const Geoid* geoid /* =0 */ )const{ assert( !IsEmpty() ); assert( !sl.IsEmpty() ); assert( ! geoid || geoid->IsDefined() ); HalfSegment hs1, hs2; double result = std::numeric_limits::max(); for( int i = 0; i < Size(); i++ ) { Get( i, hs1 ); if( hs1.IsLeftDomPoint() ) { for( int j = 0; j < sl.Size(); j++ ) { sl.Get( j, hs2 ); if( hs1.Intersects( hs2, geoid ) ){ return 0.0; } result = MIN( result, hs1.Distance( hs2, geoid ) ); } } } return result; } template class Array> double SimpleLineT::Distance(const Rectangle<2>& r, const Geoid* geoid /*=0*/)const{ assert( !IsEmpty() ); assert( r.IsDefined() ); assert( !geoid || geoid->IsDefined() ); if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." < sll(0); toLine(sll); return sll.Distance( r, geoid ); } template class Array> bool SimpleLineT::Intersects(const Rectangle<2>& r, const Geoid* geoid ) const{ if(!IsDefined() || !r.IsDefined()){ return false; } if(!BoundingBox().Intersects(r,geoid)){ return false; } HalfSegment hs; for( int i = 0; i < Size(); i++ ) { Get( i, hs); if(hs.Intersects(r,geoid)){ return true; } } return false; } template class Array> bool SimpleLineT::AtPosition( double pos, Point& p, const Geoid* geoid /* = 0 */) const { assert( ! geoid || geoid->IsDefined() ); if(IsEmpty() || (geoid && !geoid->IsDefined()) ){ // subsumes !IsDefined() p.SetDefined( false ); return false; } if( !startSmaller ) pos = length - pos; LRS lrs( pos, 0 ); int lrsPos; if( !Find( lrs,lrsPos ) ){ p.SetDefined( false ); return false; } LRS lrs2; lrsArray.Get( lrsPos, lrs2 ); HalfSegment hs; segments.Get( lrs2.hsPos, &hs ); p = hs.AtPosition( pos - lrs2.lrsPos, geoid ); p.SetDefined( true ); return true; } template class Array> bool SimpleLineT::AtPosition( double pos, bool startsSmaller, Point& p, const Geoid* geoid /* = 0 */) const { if (IsDefined() && 0.0 <= pos && pos <= length){ if(startSmaller == startsSmaller) return AtPosition(pos, p, geoid); else return AtPosition(length - pos,p,geoid); } else{ p.SetDefined(false); return false; } } /* ~AtPoint~ */ template class Array> bool SimpleLineT::AtPoint(const Point& p, const bool startsSmaller, double& result, const Geoid* geoid /*= 0*/) const{ return AtPoint(p, startsSmaller, 0.0, result, geoid); } template class Array> bool SimpleLineT::AtPoint( const Point& p, double& result, double tolerance /*=0.0*/, const Geoid* geoid /*=0*/) const { return AtPoint(p,this->startSmaller, tolerance, result, geoid); } template class Array> bool SimpleLineT::AtPoint( const Point& p, bool startsSmaller, double tolerance, double& result, const Geoid* geoid /*=0*/) const { assert( !IsEmpty() ); assert( p.IsDefined() ); if( IsEmpty() || !p.IsDefined() || (geoid && !geoid->IsDefined()) ){ return false; } if(geoid){ cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented." <= 0; pos-- ) { segments.Get( pos, hs ); if( hs.IsLeftDomPoint() && hs.Contains( p, geoid ) ) { found = true; break; } } } if( found ){ LRS lrs; lrsArray.Get( hs.attr.edgeno, lrs ); segments.Get( lrs.hsPos, &hs ); result = lrs.lrsPos + p.Distance( hs.GetDomPoint() ); if(!startsSmaller) result = length - result; if (tolerance != 0.0) { if( AlmostEqualAbsolute( result, 0.0, tolerance ) ) result = 0.0; else if(AlmostEqualAbsolute( result, length, tolerance)) result = length; } else { if (AlmostEqual(result,0.0) || result < 0.0) result = 0.0; else if (AlmostEqual(result, length) || result > length) result = length; } assert( result >= 0.0 && result <= length ); return true; } return false; } template class Array> template class Array2> void SimpleLineT::SubLine( double pos1, double pos2, SimpleLineT& l ) const { l.Clear(); if( !IsDefined() ){ l.SetDefined( false ); return; } l.SetDefined( true ); if( pos1 < 0 ){ pos1 = 0; } else if( pos1 > length ){ pos1 = length; } if( pos2 < 0 ){ pos2 = 0; } else if( pos2 > length ){ pos2 = length; } if( AlmostEqual( pos1, pos2 ) || pos1 > pos2 ){ return; } double start = pos1; double end = pos2; if(!this->startSmaller ) { start = length - pos2; end = length - pos1; } // First search for the first half segment LRS lrs( start, 0 ); int lrsPos = 0; Find( lrs, lrsPos ); LRS lrs2; lrsArray.Get( lrsPos, lrs2 ); HalfSegment hs; segments.Get( lrs2.hsPos, hs ); l.Clear(); l.StartBulkLoad(); int edgeno = 0; HalfSegment auxHs; if( hs.SubHalfSegment( start - lrs2.lrsPos, end - lrs2.lrsPos, auxHs ) ) { auxHs.attr.edgeno = ++edgeno; l += auxHs; auxHs.SetLeftDomPoint( !auxHs.IsLeftDomPoint() ); l += auxHs; } while( lrsPos < lrsArray.Size() - 1 && (lrs2.lrsPos + hs.Length() < end || AlmostEqual( lrs2.lrsPos + hs.Length(), end ) ) ) { // Get the next half segment in the sequence lrsArray.Get( ++lrsPos, lrs2 ); segments.Get( lrs2.hsPos, hs ); if( hs.SubHalfSegment( start - lrs2.lrsPos, end - lrs2.lrsPos, auxHs)){ auxHs.attr.edgeno = ++edgeno; l += auxHs; auxHs.SetLeftDomPoint( !auxHs.IsLeftDomPoint() ); l += auxHs; } } l.EndBulkLoad(); Point pStartPoint ( true ); AtPosition ( pos1, startSmaller, pStartPoint ); Point pEndPoint ( true ); AtPosition ( pos2, startSmaller, pEndPoint ); if ( pStartPoint.GetX() < pEndPoint.GetX() || ( pStartPoint.GetX() == pEndPoint.GetX() && pStartPoint.GetY() < pEndPoint.GetY())) { l.SetStartSmaller(true); } else { l.SetStartSmaller(false); } } template class Array> template class Array2> void SimpleLineT::SubLine( double pos1, double pos2, bool startsSmaller, SimpleLineT & l ) const { l.Clear(); if( !IsDefined() ){ l.SetDefined( false ); return; } l.SetDefined( true ); if( pos1 < 0 ){ pos1 = 0; } else if( pos1 > length ){ pos1 = length; } if( pos2 < 0 ){ pos2 = 0; } else if( pos2 > length ){ pos2 = length; } if( AlmostEqual( pos1, pos2 ) || pos1 > pos2 ){ return; } double start = pos1; double end = pos2; if( !startsSmaller) { start = length - pos2; end = length - pos1; } // First search for the first half segment LRS lrs( start, 0 ); int lrsPos = 0; Find( lrs, lrsPos ); LRS lrs2; lrsArray.Get( lrsPos, lrs2 ); HalfSegment hs; segments.Get( lrs2.hsPos, hs ); l.Clear(); l.StartBulkLoad(); int edgeno = 0; HalfSegment auxHs; if( hs.SubHalfSegment( start - lrs2.lrsPos, end - lrs2.lrsPos, auxHs ) ) { auxHs.attr.edgeno = ++edgeno; l += auxHs; auxHs.SetLeftDomPoint( !auxHs.IsLeftDomPoint() ); l += auxHs; } while( lrsPos < lrsArray.Size() - 1 && ( lrs2.lrsPos + hs.Length() < end|| AlmostEqual( lrs2.lrsPos + hs.Length(), end ) ) ) { // Get the next half segment in the sequence lrsArray.Get( ++lrsPos, lrs2 ); segments.Get( lrs2.hsPos, hs ); if( hs.SubHalfSegment( start - lrs2.lrsPos, end - lrs2.lrsPos, auxHs)){ auxHs.attr.edgeno = ++edgeno; l += auxHs; auxHs.SetLeftDomPoint( !auxHs.IsLeftDomPoint() ); l += auxHs; } } l.EndBulkLoad(); Point pStartPoint ( true ); AtPosition ( pos1, startsSmaller, pStartPoint ); Point pEndPoint ( true ); AtPosition ( pos2, startsSmaller, pEndPoint ); if ( pStartPoint.GetX() < pEndPoint.GetX() || ( pStartPoint.GetX() == pEndPoint.GetX() && pStartPoint.GetY() < pEndPoint.GetY())) { l.SetStartSmaller(true); } else { l.SetStartSmaller(false); } } template class Array> template class Array2, template class Array3> void SimpleLineT::Crossings( const SimpleLineT& l, PointsT& result, const Geoid* geoid /*=0*/ ) const { result.Clear(); if( !IsDefined() || !l.IsDefined() ) { result.SetDefined( false ); return; } result.SetDefined( true ); if( IsEmpty() || l.IsEmpty() || (geoid && !geoid->IsDefined())){ return; } assert( IsOrdered() && l.IsOrdered() ); HalfSegment hs1, hs2; Point p; 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 } template class Array> template class Array2> bool SimpleLineT::Intersects(const SimpleLineT & 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() || l.IsEmpty()){ return false; } if(!geoid && !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, geoid ) ) return true; } } } } return false; } template class Array> bool SimpleLineT::SelectInitialSegment( const Point &startPoint, const double tolerance, const Geoid* geoid /* = 0 */){ assert( IsDefined() ); assert( startPoint.IsDefined() ); assert( ! geoid || geoid->IsDefined() ); if(isCycle ){ return false; } bool success = Find(startPoint, currentHS, false); if ( !success || currentHS < 0 || currentHS >= Size() ){ currentHS = -1; if (tolerance > 0.0) { // try to find the point with minimum distance to startPoint, // where the distance is smaller than tolerance double minDist = tolerance; // currentHS is -1 double distance = 0.0; for(int pos=0; pos class Array> bool SimpleLineT::SelectSubsequentSegment() { assert( IsDefined() ); HalfSegment hs; if( isCycle || currentHS < 0 ){ return false; } segments.Get(currentHS, hs); int partner = hs.attr.partnerno; HalfSegment nexths; // look at position before currentHS's partner if( partner>0 ) { currentHS = partner - 1; segments.Get(currentHS, nexths); if ( AlmostEqual(nexths.GetDomPoint(), hs.GetSecPoint()) ) { return true; } } // look at position after currentHS's partner if( partner < Size()-1 ) { currentHS = partner + 1; segments.Get(currentHS, nexths); if ( AlmostEqual(nexths.GetDomPoint(), hs.GetSecPoint()) ) { return true; } } // No subsequent HalfSegment found: currentHS = -1; return false; } template class Array> bool SimpleLineT::getWaypoint( Point &destination ) const{ assert( IsDefined() ); if( isCycle || currentHS < 0 || currentHS >= Size() ) { destination.SetDefined( false ); return false; } HalfSegment hs; segments.Get(currentHS, hs); destination = hs.GetSecPoint(); destination.SetDefined( true ); return true; } template class Array> template class Array2> void SimpleLineT::fromLine(const LineT& src) { fromLine(src,true); } template class Array> template class Array2> void SimpleLineT::fromLine(const LineT& src, const bool smaller) { Clear(); // remove all old segments if(!src.IsDefined()){ SetDefined(false); return; } SetDefined(true); if(src.IsEmpty()){ return; } StartBulkLoad(); int edgeno = 0; HalfSegment hs; for(int i=0;i class Array> template class Array2> void SimpleLineT::toLine(LineT& result)const{ result.Clear(); if(!IsDefined()){ result.SetDefined(false); return; } result.SetDefined(true); HalfSegment hs; result.StartBulkLoad(); for(int i=0;i class Array> void SimpleLineT::SetPartnerNo(){ if( !IsDefined() || segments.Size()==0){ return; } DbArray TMP((segments.Size()+1)/2); HalfSegment hs1; HalfSegment hs2; for(int i=0; i class Array> bool SimpleLineT::computePolyline(){ if( !IsDefined() ) { return false; } lrsArray.clean(); isCycle = false; length = 0; if( segments.Size()==0){ // an empty line return true; } // the halfsegment array has to be sorted, realminized and // the partnernumber must be set correctly // step 1: try to find the start of the polyline and check for branches int size = segments.Size(); int start = -1; int end = -1; int count = 0; int pos = 0; HalfSegment hs; Point p1; Point p2; while(pos2){ // branch detected return false; } else { pos++; p1 = p2; if(pos=0){ // loop detected return false; } pos = 0; if(start<0){ // line is a cycle isCycle=true; } else { isCycle = false; pos = start; } // the line has two or zero endpoints, may be several components std::vector used(size,false); int noUnused = size; HalfSegment hs1; HalfSegment hs2; lrsArray.resize(segments.Size()/2 + 1); double lrsPos = 0.0; int hsPos = pos; int edge = 0; while(noUnused > 0){ segments.Get(hsPos,hs1); used[hsPos]=true; // segment is used noUnused--; int partnerpos = hs1.attr.partnerno; segments.Get(partnerpos,hs2); used[partnerpos] = true; // partner is used noUnused--; // store edgenumber HalfSegment HS1 = hs1; HalfSegment HS2 = hs2; HS1.attr.edgeno = edge; HS2.attr.edgeno = edge; edge++; segments.Put(hsPos,HS1); segments.Put(partnerpos,HS2); lrsArray.Append(LRS(lrsPos,hsPos)); lrsPos += hs1.Length(); Point p1 = hs2.GetDomPoint(); if(noUnused > 0){ bool found = false; if(partnerpos > 0 && !used[partnerpos-1]){ // check left side segments.Get(partnerpos-1,hs2); Point p2 = hs2.GetDomPoint(); if(AlmostEqual(p1,p2)){ // extension found found = true; hsPos = partnerpos-1; } } if(!found && (partnerpos < (size-1) && !used[partnerpos+1])){ segments.Get(partnerpos+1,hs2); Point p2 = hs2.GetDomPoint(); if(AlmostEqual(p1,p2)){ found = true; hsPos = partnerpos+1; } } if(!found){ // no extension found return false; } } } lrsArray.Append(LRS(lrsPos,hsPos)); length = lrsPos; return true; } template class Array> int SimpleLineT::Compare(const Attribute* arg)const{ const SimpleLineT * line = static_cast *>(arg); return Compare(line); } template class Array> template class Array2> int SimpleLineT::Compare(const SimpleLineT* line)const{ if(!IsDefined() && !line->IsDefined()){ return true; } if(!IsDefined()){ return -1; } if(!line->IsDefined()){ return 1; } if(segments.Size() < line->segments.Size()){ return -1; } if(segments.Size() > line->segments.Size()){ return 1; } if(startSmaller && !line->startSmaller) { return 1; } if(!startSmaller && line->startSmaller) { return -1; } int cmp; HalfSegment hs1; HalfSegment hs2; for(int i=0;isegments.Get(i,hs2); if( (cmp = hs1.Compare(hs2)) !=0){ return cmp; } } return 0; } template class Array> std::ostream& SimpleLineT::Print(std::ostream& o)const{ o << "SimpleLineT def =" << IsDefined() << " size = " << Size() << " startSmaller: " << startSmaller << endl; for (int i = 0; i < Size(); i++) { HalfSegment hs; Get(i, hs); if (hs.IsLeftDomPoint()) hs.Print(o); } return o; } template class Array> double SimpleLineT::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 && (i class Array> std::vector >* SimpleLineT::SplitAtPPoints( PointsT* pts) { Point curPoint(true); double pos; SimpleLineT res(0); std::vector >* result = new std::vector >(); result->clear(); std::vector* splitPositions= new std::vector(); splitPositions->clear(); splitPositions->push_back(0.0); splitPositions->push_back(Length()); for (int i = 0; i < pts->Size(); i++) { pts->Get(i,curPoint); AtPoint(curPoint, pos); splitPositions->push_back(pos); } stable_sort(splitPositions->begin(), splitPositions->end()); double from = 0.0; double to = from; for (size_t j = 0; j < splitPositions->size(); j++) { to = splitPositions->at(j); if (to != from) { SubLine(from, to, res); result->push_back(res); from = to; } } if (from != Length()) { SubLine(from, Length(), res); result->push_back(res); } splitPositions->clear(); delete splitPositions; return result; } template class Array> std::ostream& operator<<(std::ostream& o, const SimpleLineT& cl){ cl.Print(o); return o; }