Files
secondo/Algebras/Spatial/SimpleLineTImpl.h
2026-01-23 17:03:45 +08:00

1366 lines
35 KiB
C++

/*
----
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<template<typename T> class Array>
template<template<typename T2> class Array2>
SimpleLineT<Array>::SimpleLineT(const LineT<Array2>& 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<template<typename T> class Array>
void SimpleLineT<Array>::StartBulkLoad(){
isOrdered = false;
SetDefined( true );
}
/*
~Operator +=~
Appends an HalfSegment during BulkLoading.
*/
template<template<typename T> class Array>
SimpleLineT<Array>& SimpleLineT<Array>::operator+=(const HalfSegment& hs){
assert(!isOrdered && IsDefined());
segments.Append(hs);
return *this;
}
template<template<typename T> class Array>
void SimpleLineT<Array>::Add(const HalfSegment& hs) {
assert(!isOrdered && IsDefined());
segments.Append(hs);
}
template<template<typename T> class Array>
bool SimpleLineT<Array>::EndBulkLoad(){
if( !IsDefined() ) {
Clear();
SetDefined( false );
}
// Sort the segments
Sort();
// Realminize the segments
Array<HalfSegment>* 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<template<typename T> class Array>
Point SimpleLineT<Array>::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<template<typename T> class Array>
Point SimpleLineT<Array>::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<template<typename T> class Array>
Point SimpleLineT<Array>::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<template<typename T> class Array>
Point SimpleLineT<Array>::EndPoint( bool startsSmaller ) const {
if( IsEmpty() || !IsDefined() ) return Point( false );
if (startsSmaller == startSmaller) return EndPoint();
else return StartPoint();
}
template<template<typename T> class Array>
bool SimpleLineT<Array>::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<template<typename T> class Array>
template<template<typename T2> class Array2>
bool SimpleLineT<Array>::Inside(const SimpleLineT<Array2> & 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<template<typename T> class Array>
template<template<typename T2> class Array2>
void SimpleLineT<Array>::Intersection(const Point& p, PointsT<Array2>& 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<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T2> class Array3>
void SimpleLineT<Array>::Intersection(const PointsT<Array2>& ps,
PointsT<Array3>& 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;i<ps.Size(); i++){
ps.Get(i,p);
if(this->Contains(p,geoid)){
result += p;
}
}
result.EndBulkLoad(false,false,false);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Intersection( const LineT<Array2>& l,
SimpleLineT<Array3>& result,
const Geoid* geoid/*=0*/ ) const
{
SetOp(*this,l,result,avlseg::intersection_op, geoid);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Intersection( const SimpleLineT<Array2>& l,
SimpleLineT<Array3>& result,
const Geoid* geoid/*=0*/ ) const
{
SetOp(*this,l,result,avlseg::intersection_op, geoid);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Intersection(const RegionT<Array2>& r,
SimpleLineT<Array3>& result,
const Geoid* geoid/*=0*/) const{
r.Intersection(*this,result,geoid);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2>
void SimpleLineT<Array>::Minus(const Point& p, SimpleLineT<Array2>& result,
const Geoid* geoid/*=0*/) const {
result.Clear();
if(!IsDefined() || !p.IsDefined()){
result.SetDefined(false);
return;
}
result.CopyFrom(this);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Minus(const PointsT<Array2>& ps,
SimpleLineT<Array3>& result,
const Geoid* geoid/*=0*/) const {
result.Clear();
if(!IsDefined() || !ps.IsDefined() || (geoid&& !geoid->IsDefined()) ){
result.SetDefined(false);
return;
}
result.CopyFrom(this);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Minus(const LineT<Array2>& line,
SimpleLineT<Array3>& result,
const Geoid* geoid/*=0*/) const{
SetOp(*this,line,result,avlseg::difference_op,geoid);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Minus(const RegionT<Array2>& region,
SimpleLineT<Array3>& result,
const Geoid* geoid/*=0*/) const{
SetOp(*this,region, result,avlseg::difference_op,geoid);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Minus(const SimpleLineT<Array2>& line,
SimpleLineT<Array3>& result,
const Geoid* geoid/*=0*/) const{
SetOp(*this,line,result,avlseg::difference_op,geoid);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2>
void SimpleLineT<Array>::Union(const Point& p, SimpleLineT<Array2>& result,
const Geoid* geoid/*=0*/) const{
result.Clear();
if(!IsDefined() || !p.IsDefined() || (geoid&& !geoid->IsDefined()) ){
result.SetDefined(false);
return;
}
result.CopyFrom(this);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Union(const PointsT<Array2>& ps,
SimpleLineT<Array3>& result,
const Geoid* geoid/*=0*/) const{
result.Clear();
if(!IsDefined() || !ps.IsDefined() || (geoid&& !geoid->IsDefined())){
result.SetDefined(false);
return;
}
result.CopyFrom(this);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Union(const LineT<Array2>& line, LineT<Array3>& result,
const Geoid* geoid/*=0*/) const{
SetOp(*this, line, result, avlseg::union_op,geoid);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Union(const RegionT<Array2>& region,
RegionT<Array3>& result,
const Geoid* geoid/*=0*/) const{
region.Union(*this,result,geoid);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Union(const SimpleLineT<Array2>& line,
LineT<Array3>& result,
const Geoid* geoid/*=0*/) const{
SetOp(*this, line, result, avlseg::union_op,geoid);
}
template<template<typename T> class Array>
double SimpleLineT<Array>::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<double>::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<template<typename T> class Array>
template<template<typename T2> class Array2>
double SimpleLineT<Array>::Distance(const PointsT<Array2>& ps,
const Geoid* geoid /* =0 */)const{
assert( !IsEmpty() );
assert( !ps.IsEmpty() );
assert( ! geoid || geoid->IsDefined() );
HalfSegment hs;
Point p;
double result = std::numeric_limits<double>::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<template<typename T> class Array>
template<template<typename T2> class Array2>
double SimpleLineT<Array>::Distance(const SimpleLineT<Array2>& sl,
const Geoid* geoid /* =0 */ )const{
assert( !IsEmpty() );
assert( !sl.IsEmpty() );
assert( ! geoid || geoid->IsDefined() );
HalfSegment hs1, hs2;
double result = std::numeric_limits<double>::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<template<typename T> class Array>
double SimpleLineT<Array>::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."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
LineT<Array> sll(0);
toLine(sll);
return sll.Distance( r, geoid );
}
template<template<typename T> class Array>
bool SimpleLineT<Array>::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<template<typename T> class Array>
bool SimpleLineT<Array>::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<template<typename T> class Array>
bool SimpleLineT<Array>::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<template<typename T> class Array>
bool SimpleLineT<Array>::AtPoint(const Point& p, const bool startsSmaller,
double& result,
const Geoid* geoid /*= 0*/) const{
return AtPoint(p, startsSmaller, 0.0, result, geoid);
}
template<template<typename T> class Array>
bool SimpleLineT<Array>::AtPoint( const Point& p,
double& result,
double tolerance /*=0.0*/,
const Geoid* geoid /*=0*/) const {
return AtPoint(p,this->startSmaller, tolerance, result, geoid);
}
template<template<typename T> class Array>
bool SimpleLineT<Array>::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."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
bool found = false;
HalfSegment hs;
int pos;
if( Find( p, pos ) ) {
found = true;
segments.Get( pos, &hs );
} else if( pos < Size() ) {
for( ; pos >= 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<template<typename T> class Array>
template<template<typename T2> class Array2>
void SimpleLineT<Array>::SubLine( double pos1, double pos2,
SimpleLineT<Array2>& 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<template<typename T> class Array>
template<template<typename T2> class Array2>
void SimpleLineT<Array>::SubLine( double pos1, double pos2,
bool startsSmaller, SimpleLineT<Array2> & 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<template<typename T> class Array>
template<template<typename T2> class Array2,
template<typename T3> class Array3>
void SimpleLineT<Array>::Crossings( const SimpleLineT<Array2>& l,
PointsT<Array3>& 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<template<typename T> class Array>
template<template<typename T2> class Array2>
bool SimpleLineT<Array>::Intersects(const SimpleLineT<Array2> & 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<template<typename T> class Array>
bool SimpleLineT<Array>::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<Size(); pos++) {
// scan all dominating point, save the index of the HalfSegment with
// the currently smallest distance to startPoint to currentHS and the
// current minimum distance to minDist
HalfSegment hs;
segments.Get( pos, hs );
distance = hs.GetDomPoint().Distance(startPoint, geoid);
if (distance <= minDist) {
minDist = distance;
currentHS = pos;
}
}
if (currentHS != -1) {
return true;
}
}
return false;
}
return true;
}
template<template<typename T> class Array>
bool SimpleLineT<Array>::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<template<typename T> class Array>
bool SimpleLineT<Array>::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<template<typename T> class Array>
template<template<typename T2> class Array2>
void SimpleLineT<Array>::fromLine(const LineT<Array2>& src)
{
fromLine(src,true);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2>
void SimpleLineT<Array>::fromLine(const LineT<Array2>& 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<src.Size();i++){
src.Get(i,hs);
if(hs.IsLeftDomPoint()){
hs.attr.edgeno = edgeno;
edgeno++;
(*this) += hs;
hs.SetLeftDomPoint(false);
(*this) += hs;
}
}
EndBulkLoad();
SetStartSmaller(smaller);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2>
void SimpleLineT<Array>::toLine(LineT<Array2>& result)const{
result.Clear();
if(!IsDefined()){
result.SetDefined(false);
return;
}
result.SetDefined(true);
HalfSegment hs;
result.StartBulkLoad();
for(int i=0;i<segments.Size();i++){
segments.Get(i,hs);
result += hs;
}
result.EndBulkLoad();
}
template<template<typename T> class Array>
void SimpleLineT<Array>::SetPartnerNo(){
if( !IsDefined() || segments.Size()==0){
return;
}
DbArray<int> TMP((segments.Size()+1)/2);
HalfSegment hs1;
HalfSegment hs2;
for(int i=0; i<segments.Size(); i++){
segments.Get(i,hs1);
if(hs1.IsLeftDomPoint()){
TMP.Put(hs1.attr.edgeno, i);
} else {
int lpp;
TMP.Get(hs1.attr.edgeno,lpp);
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;
segments.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;
segments.Put(i,right);
segments.Put(leftpos,left);
}
}
TMP.Destroy();
}
template<template<typename T> class Array>
bool SimpleLineT<Array>::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(pos<size){
count = 1;
segments.Get(pos,hs);
p1 = hs.GetDomPoint();
pos++;
if(pos<size){
segments.Get(pos,hs);
p2 = hs.GetDomPoint();
}
while(pos<size && AlmostEqual(p1,p2)){
count++;
if(count>2){ // branch detected
return false;
} else {
pos++;
p1 = p2;
if(pos<size){
segments.Get(pos,hs);
p2 = hs.GetDomPoint();
}
}
}
if(count==1){
if(start<0){
start = pos - 1;
} else if(end < 0){
end = pos - 1;
} else { // third end detected
return false;
}
}
}
if(start<0 && end>=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<bool> 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<template<typename T> class Array>
int SimpleLineT<Array>::Compare(const Attribute* arg)const{
const SimpleLineT<Array> * line =
static_cast<const SimpleLineT<Array> *>(arg);
return Compare(line);
}
template<template<typename T> class Array>
template<template<typename T2> class Array2>
int SimpleLineT<Array>::Compare(const SimpleLineT<Array2>* 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;i<segments.Size();i++){
segments.Get(i,hs1);
line->segments.Get(i,hs2);
if( (cmp = hs1.Compare(hs2)) !=0){
return cmp;
}
}
return 0;
}
template<template<typename T> class Array>
std::ostream& SimpleLineT<Array>::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<template<typename T> class Array>
double SimpleLineT<Array>::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<Size())) ;i++){
HalfSegment hs;
Get( i, hs );
if( hs.IsLeftDomPoint() ){
length += hs.LengthOrthodrome(geoid, valid);
};
}
return length;
}
template<template<typename T> class Array>
std::vector<SimpleLineT<Array> >* SimpleLineT<Array>::SplitAtPPoints(
PointsT<Array>* pts)
{
Point curPoint(true);
double pos;
SimpleLineT<Array> res(0);
std::vector<SimpleLineT<Array> >* result =
new std::vector<SimpleLineT<Array> >();
result->clear();
std::vector<double>* splitPositions= new std::vector<double>();
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<template<typename T> class Array>
std::ostream& operator<<(std::ostream& o, const SimpleLineT<Array>& cl){
cl.Print(o);
return o;
}