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

2403 lines
57 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
----
//[_] [\_]
*/
#ifndef LineTImpl_H
#define LineTImpl_H
#include "RegionCreator.h"
#include "AVLSegment.h"
#include "LineT.h"
#include "../../Tools/Flob/MMDbArray.h"
#include <stack>
bool douglas_peucker(const std::vector<Point>& 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<Point>& orig, // original line
const double epsilon, // maximum derivation
bool* use, // result
const bool force,
const Geoid* geoid); // current range
template<template<typename T1>class Array1,
template<typename T2> class Array2>
void SelectFirst_ll( const LineT<Array1>& L1,
const LineT<Array2>& 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;
}
}
template<template<typename T1>class Array1,
template<typename T2> class Array2>
void SelectNext_ll( const LineT<Array1>& L1,
const LineT<Array2>& 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~
*/
template<template<typename T>class Array>
inline LineT<Array>::LineT( const int n ) :
StandardSpatialAttribute<2>(true),
line( n ),
bbox( false ),
ordered( true ),
noComponents( 0 ),
length( 0.0 ),
currentHS( -1 )
{ }
template<template<typename T>class Array>
inline LineT<Array>::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);
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
inline LineT<Array>::LineT( const LineT<Array2>& 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);
}
template<template<typename T>class Array>
inline void LineT<Array>::Destroy()
{
line.Destroy();
}
template<template<typename T>class Array>
inline double LineT<Array>::Length() const
{
assert( IsDefined() );
return length;
}
template<template<typename T>class Array>
inline const Rectangle<2> LineT<Array>::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; i<Size() ;i++){
HalfSegment hs;
Get( i, hs );
if( hs.IsLeftDomPoint() ){
if(!geobbox.IsDefined()){
geobbox = hs.BoundingBox(geoid);
} else {
geobbox = geobbox.Union(hs.BoundingBox(geoid));
}
} // else: ignore inverse HalfSegments
} // end for
return geobbox;
} // else: euclidean MBR
return bbox;
}
template<template<typename T>class Array>
inline bool LineT<Array>::IsOrdered() const
{
return ordered;
}
template<template<typename T>class Array>
inline bool LineT<Array>::IsEmpty() const
{
return !IsDefined() || (line.Size() == 0);
}
template<template<typename T>class Array>
inline int LineT<Array>::Size() const
{
return line.Size();
}
template<template<typename T>class Array>
inline void LineT<Array>::Get( const int i, HalfSegment& hs ) const
{
assert( IsDefined() );
assert(i>=0);
assert(i<line.Size());
line.Get( i, &hs );
}
template<template<typename T>class Array>
inline void LineT<Array>::Resize(const int newSize){
if(newSize>Size()){
line.resize(newSize);
}
}
template<template<typename T>class Array>
inline void LineT<Array>::TrimToSize(){
line.TrimToSize();
}
template<template<typename T>class Array>
inline void LineT<Array>::Put( const int i, const HalfSegment& hs )
{
assert( IsDefined() );
line.Put( i, hs );
}
template<template<typename T>class Array>
inline void LineT<Array>::SelectFirst() const
{
if( IsEmpty() )
pos = -1;
else pos = 0;
}
template<template<typename T>class Array>
inline void LineT<Array>::SelectNext() const
{
if( pos >= 0 && pos < Size() - 1 )
pos++;
else pos = -1;
}
template<template<typename T>class Array>
inline bool LineT<Array>::EndOfHs() const
{
return pos == -1;
}
template<template<typename T>class Array>
inline bool LineT<Array>::GetHs( HalfSegment& hs ) const
{
assert( IsDefined() );
if( pos >= 0 && pos <= Size()-1 )
{
line.Get( pos, &hs );
return true;
}
return false;
}
template<template<typename T>class Array>
template<class LineType>
double LineT<Array>::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<double>::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~
*/
template<template<typename T>class Array>
void LineT<Array>::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.
*/
template<template<typename T>class Array>
void LineT<Array>::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<HalfSegment>* line2 = ::Realminize<Array>(line,false, robust);
line2->Sort(HalfSegmentCompare);
line.copyFrom(*line2);
line2->Destroy();
delete line2;
}
SetPartnerNo();
}
computeComponents();
TrimToSize();
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
LineT<Array>& LineT<Array>::operator=( const LineT<Array2>& 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;
}
template<template<typename T>class Array>
LineT<Array>& LineT<Array>::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;
}
template<template<typename T>class Array>
bool LineT<Array>::operator==( const LineT<Array>& 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;i<Size();i++){
line.Get(i, hs);
l.line.Get(i, lhs);
if( hs != lhs ){
return false;
}
}
return true;
}
template<template<typename T>class Array>
bool LineT<Array>::operator!=( const LineT<Array>& l ) const
{
return !( *this == l);
}
template<template<typename T>class Array>
LineT<Array>& LineT<Array>::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;
}
template<template<typename T>class Array>
LineT<Array>& LineT<Array>::operator+=(const LineT<Array>& 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;
}
template<template<typename T>class Array>
LineT<Array>& LineT<Array>::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;
}
template<template<typename T>class Array>
bool LineT<Array>::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;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool LineT<Array>::Intersects( const LineT<Array2>& 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;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool LineT<Array>::Intersects( const RegionT<Array2>& 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;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool LineT<Array>::Inside( const LineT<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() ){
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>
bool LineT<Array>::Inside( const RegionT<Array2>& 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;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool LineT<Array>::Adjacent( const RegionT<Array2>& 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;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<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 T3>class Array3>
void LineT<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(true);
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 LineT<Array>::Intersection( const LineT<Array2>& l, LineT<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 LineT<Array>::Intersection(const RegionT<Array2>& r, LineT<Array3>& result,
const Geoid* geoid/*=0*/) const{
r.Intersection(*this,result,geoid);
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void LineT<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>
void LineT<Array>::Minus(const Point& p, LineT<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 LineT<Array>::Minus(const PointsT<Array2>& ps, LineT<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 LineT<Array>::Minus(const LineT<Array2>& line, LineT<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 LineT<Array>::Minus(const RegionT<Array2>& region, LineT<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 LineT<Array>::Minus(const SimpleLineT<Array2>& line, LineT<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 LineT<Array>::Union(const Point& p, LineT<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 LineT<Array>::Union(const PointsT<Array2>& ps, LineT<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 LineT<Array>::Union(const LineT<Array2>& line, LineT<Array3>& 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;i<line.Size();i++){
line.Get(i,hs);
result += hs;
}
for(int i=0;i<this->Size();i++){
this->Get(i,hs);
result += hs;
}
result.EndBulkLoad(true,true,true);
}
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void LineT<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 LineT<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>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void LineT<Array>::Crossings( const LineT<Array2>& l, PointsT<Array3>& 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
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::Crossings(PointsT<Array2>& 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(i<size){
Get(i,hs);
p = hs.GetDomPoint();
i++;
if(!lastPoint.IsDefined()){ // first point
lastPoint = p;
count = 0;
} else if(AlmostEqual(lastPoint,p)){
count++;
} else {
if(count>2){ // crossing found
result += p;
}
lastPoint = p;
count = 1;
}
}
if(lastPoint.IsDefined() && count>2){
result += lastPoint;
}
result.EndBulkLoad();
}
template<template<typename T>class Array>
double LineT<Array>::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<double>::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;
}
template<template<typename T>class Array>
double LineT<Array>::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;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
double LineT<Array>::Distance( const PointsT<Array2>& 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<double>::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;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::DistanceSmallerThan(const LineT<Array2>& 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);
}
template<template<typename T>class Array>
double LineT<Array>::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."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
if( IsEmpty() || !r.IsDefined() || (geoid && !geoid->IsDefined()) ){
return -1;
}
assert( IsOrdered() );
HalfSegment hs;
double dist = std::numeric_limits<double>::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(d<dist){
dist = d;
}
}
}
return dist;
}
template<template<typename T>class Array>
bool LineT<Array>::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."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
HalfSegment hs;
for(int i=0;i<line.Size();i++){
line.Get(i,hs);
if(hs.IsLeftDomPoint()){
if(hs.Intersects(r,geoid)){
return true;
}
}
}
return false;
}
template<template<typename T>class Array>
double LineT<Array>::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."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
if( IsEmpty() || !r.IsDefined() || (geoid && !geoid-IsDefined()) ){
return -1;
}
assert( IsOrdered() );
HalfSegment hs;
double dist = 0;
for(int i=0; i < line.Size(); i++){
line.Get(i,hs);
if(hs.IsLeftDomPoint()){
double d = hs.MaxDistance(r,geoid);
if(d > dist){
dist = d;
}
}
}
return dist;
}
template<template<typename T>class Array>
int LineT<Array>::NoComponents() const {
return noComponents;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::Translate( const Coord& x, const Coord& y,
LineT<Array2>& 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);
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::Rotate( const Coord& x, const Coord& y,
const double alpha,
LineT<Array2>& 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
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::Scale( const Coord& sx, const Coord& sy,
LineT<Array2>& 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
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::Transform( RegionT<Array2>& 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<HalfSegment>* halfsegments = new Array<HalfSegment>(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<Array>::setPartnerNo(halfsegments);
RegionCreator<Array>::createRegion(halfsegments,&result);
halfsegments->destroyIfNonPersistent();
delete halfsegments;
delete[] usage;
delete[] critical;
}
template<template<typename T>class Array>
void LineT<Array>::Realminize(){
// special case: empty line
if(!IsDefined()){
line.clean();
return;
}
LineT<Array> tmp(0);
Realminize2(*this,tmp);
*this = tmp;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::Boundary(PointsT<Array2>* 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;i<size;i++){
bool common = false;
Get(i,hs);
p=hs.GetDomPoint();
if(i>0){
Get(i-1,hs_n);
if(p==hs_n.GetDomPoint()){
common=true;
}
}
if(i<size-1){
Get(i+1,hs_n);
if(p==hs_n.GetDomPoint()){
common=true;
}
}
if(!common){
*result += p;
}
}
result->EndBulkLoad(false,false);
}
template<template<typename T>class Array>
bool LineT<Array>::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 );
}
template<template<typename T>class Array>
bool LineT<Array>::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 );
}
template<template<typename T>class Array>
void LineT<Array>::SetPartnerNo() {
if(!IsDefined() || line.Size()==0){
return;
}
// reserve a slot for each edgeno
int tmpsize = (line.Size()+1)/2;
DbArray<int> TMP(tmpsize);
// intialize the array (it's only needed for
// wrong sorted halfsegments)
for(int i=0;i<tmpsize+1;i++){
TMP.Put(i,-1);
}
HalfSegment hs1;
HalfSegment hs2;
int lpp;
for(int i=0; i<line.Size(); i++){
line.Get(i,hs1);
TMP.Get(hs1.attr.edgeno,lpp);
if(hs1.IsLeftDomPoint()){
if(lpp>=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();
}
template<template<typename T>class Array>
bool LineT<Array>::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;
}
template<template<typename T>class Array>
bool LineT<Array>::GetNextSegments( const int poshs, const HalfSegment& hs,
std::vector<bool>& visited,
int& posnexths, HalfSegment& nexths,
std::stack< std::pair<int, HalfSegment> >& 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.
*/
template<template<typename T>class Array>
int LineT<Array>::getUnusedExtension(int startPos,const Array<bool>& 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 && pos<size){
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++;
}
}
}
return -1;
}
template<template<typename T>class Array>
void LineT<Array>::collectFace(int faceno, int startPos, Array<bool>& used){
std::set<int> 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.
*/
template<template<typename T>class Array>
void LineT<Array>::computeComponents() {
length = 0.0;
noComponents = 0;
bbox.SetDefined(false);
if(!IsDefined() || Size()==0){
return;
}
Array<bool> used(line.Size());
for(int i=0;i<line.Size();i++){
used.Append(false);
}
int faceno = 0;
bool u;
for(int i=0;i<line.Size();i++){
used.Get(i,u);
if(!(u)){ // an unused halfsegment
collectFace(faceno,i,used);
faceno++;
}
}
noComponents = faceno;
used.Destroy();
}
template<template<typename T>class Array>
void LineT<Array>::Sort()
{
assert( !IsOrdered() );
line.Sort( HalfSegmentCompare );
ordered = true;
}
template<template<typename T>class Array>
void LineT<Array>::RemoveDuplicates()
{
assert( IsOrdered() );
int size = line.Size();
if( size == 0 ){
// nothing to do
return;
}
int newEdgeNumbers[size]; // mapping oldnumber -> newnumber
for(int i=0;i<size;i++){
newEdgeNumbers[i] = -1;
}
int newedge = 0; // next unused edge number
HalfSegment tmp;
HalfSegment last;
HalfSegment ptmp;
int pos = 0;
line.Get( 0, ptmp );
last = ptmp;
newEdgeNumbers[last.attr.edgeno] = newedge;
last.attr.edgeno = newedge;
line.Put(0,last);
newedge++;
for( int i = 1; i < size; i++ )
{
line.Get( i, ptmp );
tmp = ptmp;
int edge = tmp.attr.edgeno;
if( last != tmp )
// new segment found
{
pos++;
if(newEdgeNumbers[edge]<0){ // first
newEdgeNumbers[edge] = newedge;
tmp.attr.edgeno = newedge;
newedge++;
} else {
tmp.attr.edgeno = newEdgeNumbers[edge];
}
line.Put( pos, tmp );
last = tmp;
} else { // duplicate found
newEdgeNumbers[edge] = newedge-1; // use the last edge number
}
}
if( pos + 1 != size ){
// duplicates found
line.resize( pos + 1 );
}
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::WindowClippingIn( const Rectangle<2> &window,
LineT<Array2> &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();
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::WindowClippingOut( const Rectangle<2> &window,
LineT<Array2> &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();
}
template<template<typename T>class Array>
std::ostream& operator<<( std::ostream& os, const LineT<Array>& 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;
}
template<template<typename T>class Array>
size_t LineT<Array>::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;
}
template<template<typename T>class Array>
void LineT<Array>::Clear()
{
line.clean();
pos = -1;
ordered = true;
bbox.SetDefined( false );
SetDefined(true);
}
template<template<typename T>class Array>
void LineT<Array>::CopyFrom( const Attribute* right )
{
*this = *((const LineT<Array> *)right);
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::CopyFrom( const LineT<Array2>* right )
{
*this = *right;
}
template<template<typename T>class Array>
int LineT<Array>::Compare( const Attribute *arg ) const
{
return Compare( *(LineT<Array>*) arg);
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
int LineT<Array>::Compare( const LineT<Array2>& 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;
}
template<template<typename T>class Array>
LineT<Array>* LineT<Array>::Clone() const
{
return new LineT<Array>( *this );
}
template<template<typename T>class Array>
double LineT<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::ostream& LineT<Array>::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;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void LineT<Array>::Simplify(LineT<Array2>& result, const double epsilon,
const PointsT<Array3>& 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<Size();i++){
used[i] = false;
}
std::vector<Point> forward;
std::vector<Point> backward;
std::vector<Point> complete;
HalfSegment hs; // current halfsegment
result.StartBulkLoad();
int pos = 0;
int size = Size();
int egdeno=0;
while(pos<size){
// skip all halfsegments in prior runs
while(pos<size && used[pos]){
pos++;
}
if(pos<size){
// unused halfsegment found
forward.clear();
backward.clear();
int next = pos;
// trace the polyline until it ends or critical point is reached
bool done = false;
while(!done){
used[next]= true;
Get(next,hs);
forward.push_back(hs.GetDomPoint());
int partner = hs.attr.partnerno;
used[partner] = true;
Get(partner,hs);
Point p = hs.GetDomPoint();
if(importantPoints.Contains(p)){
done = true;
}else {
int s = std::max(0,partner-2);
int e = std::min(partner+3,Size());
int count =0;
HalfSegment tmp;
// search around partner for segments with an
// equal dominating point.
for(int k=s; (k<e) && (count < 2); k++){
if(k!=partner){
Get(k,tmp);
Point p2 = tmp.GetDomPoint();
if(AlmostEqual(p,p2)){
count++;
next = k;
}
}
}
done = (count != 1) || used[next];
}
}
forward.push_back(hs.GetDomPoint());
// check possible enlargement into the other direction
next = pos; // start again at pos
done = false;
do{
Get(next,hs);
Point p = hs.GetDomPoint();
// check whether next has an unique connected segment
int s = std::max(0, next-2);
int e = std::min(next+3,Size());
int count = 0;
HalfSegment tmp;
int partner = 0;
// search around next
if(importantPoints.Contains(p)){
done = true;
} else {
for(int k=s; (k<e) && (count <2); k++){
if(k!=next){
Get(k,tmp);
Point p2 = tmp.GetDomPoint();
if(AlmostEqual(p,p2)){
count++;
partner = k;
}
}
}
done = (count!=1) || used[partner];
if(!done){ // extension found
used[partner] = true;
Get(partner,hs);
next = hs.attr.partnerno;
used[next] = true;
Get(next,hs);
backward.push_back(hs.GetDomPoint());
}
}
} while(!done);
// connect backward and forward into complete
complete.clear();
for(int i=backward.size()-1; i>=0; i--){
complete.push_back(backward[i]);
}
for(unsigned int i=0;i<forward.size(); i++){
complete.push_back(forward[i]);
}
// determine all segments to use and copy them into the result
bool use[complete.size()];
douglas_peucker(complete,epsilon,use,false,geoid);
int size = complete.size();
Point last = complete[0];
for(int i=1;i<size;i++){
if(use[i]){
Point p = complete[i];
HalfSegment nhs(true,last,p);
nhs.attr.edgeno=egdeno;
result += nhs;
nhs.SetLeftDomPoint(false);
result += nhs;
egdeno++;
last = p;
}
}
}
}
result.EndBulkLoad();
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void LineT<Array>::Vertices( PointsT<Array2>* 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