Files
secondo/Algebras/Spatial/PointsTImpl.h

1465 lines
33 KiB
C
Raw Permalink Normal View History

2026-01-23 17:03:45 +08:00
/*
----
This file is part of SECONDO.
Copyright (C) 2017, University in Hagen, Department of 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 "PointsT.h"
#include "RegionT.h"
#include "SimpleLineT.h"
#include "SpatialAlgebra.h"
#include "Tools/Flob/MMDbArray.h"
template<template<typename T>class Array>
void PointsT<Array>::Sort(const bool exact /*= true*/)
{
assert( !IsOrdered() );
if(exact){
points.Sort( PointCompare );
} else{
points.Sort(PointCompareAlmost);
}
ordered = true;
}
/*
Function supporting the RemoveDuplicates function.
This function checks whether in an array of points
a point exists which is AlmostEqual to the given one.
The search is restricted to the range in array given
by the indices __min__ and __max__.
*/
template<template<typename T>class Array>
bool AlmostContains( const Array<Point>& points, const Point& p,
int min, int max, int size){
if(min>max){
return false;
}
Point pa(true);
if(min==max){ // search around the position found
// search left of min
int pos = min;
double x = p.GetX();
points.Get(pos,&pa);
while(pos>=0 && AlmostEqual(pa.GetX(),x)){
if(AlmostEqual(pa,p)){
return true;
}
pos--;
if(pos>=0){
points.Get(pos,&pa);
}
}
// search right of min
pos=min+1;
if(pos<size){
points.Get(pos,&pa);
}
while(pos<size &&AlmostEqual(pa.GetX(),x)){
if(AlmostEqual(pa,p)){
return true;
}
pos++;
if(pos<size){
points.Get(pos,&pa);
}
}
return false; // no matching point found
} else {
int mid = (min+max)/2;
points.Get(mid,&pa);
double x = pa.GetX();
double cx = p.GetX();
if(AlmostEqual(x,cx)){
return AlmostContains(points,p,mid,mid,size);
} else if(cx<x){
return AlmostContains(points,p,min,mid-1,size);
}else {
return AlmostContains(points,p,mid+1,max,size);
}
}
}
template<template<typename T>class Array>
void PointsT<Array>::RemoveDuplicates()
{
assert(IsOrdered());
//Point allPoints[points.Size()];
Array<Point> allPoints(points.Size());
Point p(true);
for(int i=0;i<points.Size();i++){
points.Get(i,p);
bool found = AlmostContains(allPoints,p,0,
allPoints.Size()-1,
allPoints.Size());
if(!found){
allPoints.Append(p);
}
}
if(allPoints.Size()!=Size()){
points.clean();
for(int i=0;i < allPoints.Size(); i++){
allPoints.Get(i,p);
points.Append(p);
}
}
allPoints.destroy();
}
template<template<typename T>class Array>
bool PointsT<Array>::Contains( const Point& p, const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( p.IsDefined() );
assert( IsOrdered() );
assert( !geoid || geoid->IsDefined() );
if( IsEmpty() )
return false;
if( !p.Inside( bbox, geoid ) )
return false;
int pos;
return Find( p, pos, false ); // find using AlmostEqual
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool PointsT<Array>::Contains( const PointsT<Array2>& ps,
const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( IsOrdered() );
assert( ps.IsDefined() );
assert( ps.IsOrdered() );
assert( !geoid || geoid->IsDefined() );
if(!IsDefined() || !ps.IsDefined() || (geoid && !geoid->IsDefined()) ){
return false;
}
if( IsEmpty() && ps.IsEmpty() )
return true;
if( IsEmpty() || ps.IsEmpty() )
return false;
if( !bbox.Contains( ps.BoundingBox(), geoid ) )
return false;
object obj;
status stat;
SelectFirst_pp( *this, ps, obj, stat );
while( stat != endsecond && stat != endboth )
{
if( obj == second || stat == endfirst )
return false;
SelectNext_pp( *this, ps, obj, stat );
}
return true;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool PointsT<Array>::Inside( const PointsT<Array2>& ps,
const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( IsOrdered() );
assert( ps.IsDefined() );
assert( ps.IsOrdered() );
assert( !geoid || geoid->IsDefined() );
return ps.Contains( *this, geoid );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool PointsT<Array>::Inside( const LineT<Array2>& l,
const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( IsOrdered() );
assert( l.IsDefined() );
assert( l.IsOrdered() );
assert( !geoid || geoid->IsDefined() );
if( IsEmpty() )
return true;
if( l.IsEmpty() )
return false;
if( !l.BoundingBox().Contains( bbox, geoid ) )
return false;
Point p(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( !l.Contains( p, geoid ) )
return false;
}
return true;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool PointsT<Array>::Inside( const RegionT<Array2>& r,
const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( IsOrdered() );
assert( r.IsDefined() );
assert( r.IsOrdered() );
assert( !geoid || geoid->IsDefined() );
if(geoid){
cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
if( IsEmpty() )
return true;
if( r.IsEmpty() )
return false;
if( !r.BoundingBox().Contains( bbox, geoid ) )
return false;
Point p(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( !r.Contains( p, geoid ) )
return false;
}
return true;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool PointsT<Array>::Intersects( const PointsT<Array2>& ps,
const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( IsOrdered() );
assert( ps.IsDefined() );
assert( ps.IsOrdered() );
assert( !geoid || geoid->IsDefined() );
if( IsEmpty() || ps.IsEmpty() || (geoid && !geoid->IsDefined()) )
return false;
if( !bbox.Intersects( ps.BoundingBox(), geoid ) )
return false;
object obj;
status stat;
SelectFirst_pp( *this, ps, obj, stat );
while( stat != endboth )
{
if( obj == both )
return true;
SelectNext_pp( *this, ps, obj, stat );
}
return false;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool PointsT<Array>::Intersects( const LineT<Array2>& l,
const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( IsOrdered() );
assert( l.IsDefined() );
assert( l.IsOrdered() );
assert( !geoid || geoid->IsDefined() );
if(geoid){
cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
if( IsEmpty() || l.IsEmpty() || (geoid && !geoid->IsDefined()))
return false;
if( !BoundingBox().Intersects( l.BoundingBox(), geoid ) )
return false;
Point p(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( l.Contains( p, geoid ) )
return true;
}
return false;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool PointsT<Array>::Intersects( const RegionT<Array2>& r,
const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( IsOrdered() );
assert( r.IsDefined() );
assert( r.IsOrdered() );
assert( !geoid || geoid->IsDefined() );
if(geoid){
cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
if( IsEmpty() || r.IsEmpty() || (geoid && !geoid->IsDefined()) )
return false;
if( !BoundingBox().Intersects( r.BoundingBox(), geoid ) )
return false;
Point p(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( r.Contains( p, geoid ) )
return true;
}
return false;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
bool PointsT<Array>::Adjacent( const RegionT<Array2>& r,
const Geoid* geoid /*=0*/ ) const
{
assert( IsDefined() );
assert( IsOrdered() );
assert( r.IsDefined() );
assert( r.IsOrdered() );
assert( !geoid || geoid->IsDefined() );
if(geoid){
cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
if( IsEmpty() || r.IsEmpty() || (geoid && !geoid->IsDefined()))
return false;
if( !BoundingBox().Intersects( r.BoundingBox(), geoid ) )
return false;
Point p(true);
bool found = false;
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( !r.Contains( p, geoid ) )
continue;
// At least one point is contained in the region
// If it is not inside the region, then the
// function will return true.
found = true;
if( r.InnerContains( p, geoid ) )
return false;
}
return found;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void PointsT<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;
}
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 PointsT<Array>::Intersection( const PointsT<Array2>& ps,
PointsT<Array3>& result,
const Geoid* geoid /*=0*/ ) const
{
result.Clear();
if( !IsDefined() || !ps.IsDefined() || (geoid && !geoid->IsDefined()) ) {
result.SetDefined( false );
return;
}
result.SetDefined( true );
assert( ordered );
assert( ps.ordered );
if( IsEmpty() || ps.IsEmpty() ){
return;
}
object obj;
status stat;
Point p(true);
SelectFirst_pp( *this, ps, obj, stat );
result.StartBulkLoad();
while( stat != endboth )
{
if( obj == both )
{
int GotPt = ps.GetPt( p );
assert( GotPt );
result += p;
}
SelectNext_pp( *this, ps, obj, stat );
}
result.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Intersection( 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 );
assert( IsOrdered() );
assert( l.IsOrdered() );
if( IsEmpty() || l.IsEmpty() )
return;
Point p(true);
result.StartBulkLoad();
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( l.Contains( p, geoid ) )
result += p;
}
result.EndBulkLoad( false, false );
}
/*
Computes the set of points that is located in r.
*/
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Intersection( const RegionT<Array2>& r,
PointsT<Array3>& result,
const Geoid* geoid /*=0*/ ) const
{
result.Clear();
if( !IsDefined() || !r.IsDefined() || (geoid && !geoid->IsDefined()) ) {
result.SetDefined( false );
return;
}
result.SetDefined( true );
assert( IsOrdered() );
assert( r.IsOrdered() );
if( IsEmpty() || r.IsEmpty() )
return;
Point p(true);
result.StartBulkLoad();
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( r.Contains( p, geoid ) )
result += p;
}
result.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Intersection(
const SimpleLineT<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 );
assert( IsOrdered() );
assert( l.IsOrdered() );
if( IsEmpty() || l.IsEmpty() )
return;
Point p(true);
result.StartBulkLoad();
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( l.Contains( p, geoid ) )
result += p;
}
result.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void PointsT<Array>::Minus( const Point& p, PointsT<Array2>& ps,
const Geoid* geoid /*=0*/ ) const
{
ps.Clear();
if( !IsDefined() || !p.IsDefined() || (geoid && !geoid->IsDefined()) ) {
ps.SetDefined( false );
return;
}
ps.SetDefined( true );
assert( ordered );
ps.StartBulkLoad();
Point pi(true);
for( int i = 0; i < Size(); i++ ) {
Get( i, pi );
if( !AlmostEqual(pi, p) )
ps += pi;
}
ps.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Minus( const PointsT<Array2>& ps, PointsT<Array3>& result,
const Geoid* geoid /*=0*/ ) const
{
result.Clear();
if( !IsDefined() || !ps.IsDefined() || (geoid && !geoid->IsDefined()) ) {
result.SetDefined( false );
return;
}
result.SetDefined( true );
assert( ordered );
assert( ps.ordered );
result.StartBulkLoad();
int size1 = this->Size();
int size2 = ps.Size();
int pos1 = 0, pos2 = 0;
Point p1(true), p2(true);
while(pos1<size1 && pos2<size2) {
this->Get(pos1, p1);
ps.Get(pos2, p2);
if( AlmostEqual(p1, p2) ) {
pos1++;
}
else if (p1 < p2) {
result += p1;
pos1++;
} else { // *p1 > *p2
pos2++;
}
}
while(pos1<size1) {
this->Get(pos1, p1);
result += p1;
pos1++;
}
result.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Minus( 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 );
assert( IsOrdered() );
assert( l.IsOrdered() );
Point p(true);
result.StartBulkLoad();
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( !l.Contains( p, geoid ) )
result += p;
}
result.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Minus( const RegionT<Array2>& r, PointsT<Array3>& result,
const Geoid* geoid /*=0*/ ) const
{
result.Clear();
if( !IsDefined() || !r.IsDefined() || (geoid && !geoid->IsDefined())) {
result.SetDefined( false );
return;
}
result.SetDefined( true );
assert( IsOrdered() );
assert( r.IsOrdered() );
Point p(true);
result.StartBulkLoad();
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( !r.Contains( p, geoid ) )
result += p;
}
result.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Minus( const SimpleLineT<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 );
assert( IsOrdered() );
assert( l.IsOrdered() );
Point p(true);
result.StartBulkLoad();
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
if( !l.Contains( p, geoid ) )
result += p;
}
result.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void PointsT<Array>::Union( 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 );
assert( ordered );
result.StartBulkLoad();
Point pi(true);
bool inserted = false;
for( int i = 0; i < Size(); i++)
{
Get( i, pi );
if( !inserted && pi == p )
inserted = true;
if( !inserted && pi > p )
{
result += p;
inserted = true;
}
result += pi;
}
if( !inserted )
result += p;
result.EndBulkLoad( false, true );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Union( const PointsT<Array2>& ps,
PointsT<Array3>& result,
const Geoid* geoid /*=0*/ ) const
{
result.Clear();
if( !IsDefined() || !ps.IsDefined() || (geoid && !geoid->IsDefined()) ) {
result.SetDefined( false );
return;
}
result.SetDefined( true );
assert( ordered );
assert( ps.ordered );
object obj;
status stat;
SelectFirst_pp( *this, ps, obj, stat );
Point p(true);
result.StartBulkLoad();
while( stat != endboth )
{
if( obj == first || obj == both )
{
int GotPt = GetPt( p );
assert( GotPt );
}
else if( obj == second )
{
int GotPt = ps.GetPt( p );
assert( GotPt );
}
result += p;
SelectNext_pp( *this, ps, obj, stat );
}
result.EndBulkLoad( false, true );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<Array>::Union( const LineT<Array2>& line, LineT<Array3>& result,
const Geoid* geoid /*=0*/ ) const{
line.Union(*this,result,geoid);
}
template<template<typename T>class Array>
template<template<typename T2>class Array2,
template<typename T3>class Array3>
void PointsT<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 PointsT<Array>::Union(const SimpleLineT<Array2>& line,
SimpleLineT<Array3>& result,
const Geoid* geoid /*=0*/) const{
line.Union(*this,result, geoid);
}
template<template<typename T>class Array>
double PointsT<Array>::Distance( const Point& p,
const Geoid* geoid /* = 0 */ ) const
{
assert( !IsEmpty() );
assert( p.IsDefined() );
assert( !geoid || geoid->IsDefined() );
double result = std::numeric_limits<double>::max();
for( int i = 0; i < Size(); i++ ){
Point pi(true);
Get( i, pi );
if( AlmostEqual( p, pi ) ){
return 0.0;
}
result = MIN( result, pi.Distance( p, geoid ) );
}
return result;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
double PointsT<Array>::Distance( const PointsT<Array2>& ps,
const Geoid* geoid /* = 0 */ ) const
{
assert( !IsEmpty() );
assert( !ps.IsEmpty() );
assert( !geoid || geoid->IsDefined() );
double result = std::numeric_limits<double>::max();
Point pi(true), pj(true);
for( int i = 0; i < Size(); i++ ){
Get( i, pi );
for( int j = 0; j < ps.Size(); j++ ){
ps.Get( j, pj );
if( AlmostEqual( pi, pj ) ){
return 0.0;
}
result = MIN( result, pi.Distance( pj, geoid ) );
}
}
return result;
}
template<template<typename T>class Array>
double PointsT<Array>::Distance( const Rectangle<2>& r,
const Geoid* geoid/*=0*/ ) const
{
assert( IsDefined() );
assert( !IsEmpty() );
assert( r.IsDefined() );
assert( !geoid || geoid->IsDefined() );
double result = std::numeric_limits<double>::max();
Point pi(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, pi );
result = MIN( result, pi.Distance( r, geoid ) );
}
return result;
}
template<template<typename T>class Array>
bool PointsT<Array>::Intersects( const Rectangle<2>& r,
const Geoid* geoid/*=0*/ ) const
{
assert( IsDefined() );
assert( !IsEmpty() );
assert( r.IsDefined() );
assert( !geoid || geoid->IsDefined() );
if(!BoundingBox().Intersects(r,geoid)){
return false;
}
Point pi(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, pi );
if(pi.Intersects(r,geoid)){
return true;
}
}
return false;
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void PointsT<Array>::Translate( const Coord& x, const Coord& y,
PointsT<Array2>& result ) const
{
result.Clear();
if( !IsDefined() ) {
result.SetDefined( false );
return;
}
result.SetDefined( true );
assert( ordered );
result.StartBulkLoad();
Point p(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
p.Translate( x, y );
result += p;
}
result.EndBulkLoad( false, false );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void PointsT<Array>::Scale( const Coord& x, const Coord& y,
PointsT<Array2>& result ) const
{
result.Clear();
if( !IsDefined() ) {
result.SetDefined( false );
return;
}
result.SetDefined( true );
result.Resize(Size());
result.StartBulkLoad();
Point p(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
p.Scale( x, y );
result += p;
}
result.EndBulkLoad( true, true );
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
void PointsT<Array>::Rotate( const Coord& x, const Coord& y,
const double alpha,
PointsT<Array2>& result ) const
{
result.Clear();
if(!IsDefined()){
result.SetDefined(false);
return;
}
result.SetDefined(true);
result.Resize(Size());
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();
Point p(true);
Point rot(true,0,0);
for( int i = 0; i < Size(); i++ )
{
Get( i, p );
rot.Set( m00*p.GetX() + m01*p.GetY() + m02,
m10*p.GetX() + m11*p.GetY() + m12);
result += rot;
}
result.EndBulkLoad( true, false );
}
template<template<typename T>class Array>
Point PointsT<Array>::theCenter() const{
Point res(true,0,0);
if(!IsDefined() || (Size()==0)){
res.SetDefined(false);
} else {
int size = Size();
double x = 0.0;
double y = 0.0;
for(int i=0;i<size;i++){
Point p(true,0,0);
points.Get(i,p);
x += p.GetX();
y += p.GetY();
}
res.Set(x/size,y/size);
}
return res;
}
template<template<typename T>class Array>
size_t PointsT<Array>::HashValue() const
{
if( IsEmpty() ) // IsEmpty() includes undef
return 0;
size_t h = 0;
for( int i = 0; i < Size() && i < 5; i++ )
{
Point p(true,0,0);
points.Get( i, &p );
h = h + (size_t)(5 * p.GetX() + p.GetY());
}
return h;
}
template<template<typename T>class Array>
bool PointsT<Array>::IsValid() const
{
if( IsEmpty() ) // IsEmpty() includes undef
return true;
Point p1(true), p2(true);
Get( 0, p1 );
if( !p1.IsDefined() ){
std::cerr << __PRETTY_FUNCTION__ << ": Undefined Point!" << std::endl;
std::cerr << "\tp1 = "; p1.Print(std::cerr); std::cerr << std::endl;
return false;
}
for( int i = 1; i < Size(); i++ )
{
Get( i, p2 );
if( !p2.IsDefined() ){
std::cerr << __PRETTY_FUNCTION__ << ": Undefined Point!" << std::endl;
std::cerr << "\tp2 = "; p2.Print(std::cerr); std::cerr << std::endl;
return false;
}
if( AlmostEqual( p1, p2 ) ){
std::cerr << __PRETTY_FUNCTION__ << ": Almost equal Points!" << endl;
std::cerr << "\tp1 = "; p1.Print(std::cerr);
std::cerr << "\n\tp2 = "; p2.Print(std::cerr); std::cerr << std::endl;
return false;
}
p1 = p2;
}
return true;
}
template<template<typename T>class Array>
void PointsT<Array>::Clear()
{
points.clean();
pos = -1;
ordered = true;
bbox.SetDefined( false );
}
template<template<typename T>class Array>
void PointsT<Array>::CopyFrom( const Attribute* right )
{
const PointsT<Array> *ps = (const PointsT<Array>*)right;
assert( ps->IsOrdered() );
*this = *ps;
}
template<template<typename T>class Array>
int PointsT<Array>::Compare( const Attribute* arg ) const
{
const PointsT<Array>* ps = (const PointsT<Array>*)arg;
return Compare(ps);
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
int PointsT<Array>::Compare( const PointsT<Array2>* ps) const{
if( !ps )
return (-2);
if(!IsDefined() && !ps->IsDefined()){
return 0;
}
if(!IsDefined()){
return -1;
}
if(!ps->IsDefined()){
return 1;
}
if( IsEmpty() && ps->IsEmpty() )
return 0;
if( IsEmpty() )
return -1;
if( ps->IsEmpty() )
return 1;
if( Size() > ps->Size() )
return 1;
if( Size() < ps->Size() )
return -1;
Point p1(true), p2(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, p1);
ps->Get( i, p2 );
if( p1 > p2 )
return 1;
if( p1 < p2 )
return -1;
}
return 0;
}
template<template<typename T>class Array>
int PointsT<Array>::CompareAlmost( const Attribute* arg ) const
{
const PointsT<Array>* ps = (const PointsT<Array>*)arg;
return CompareAlmost(ps);
}
template<template<typename T>class Array>
template<template<typename T2>class Array2>
int PointsT<Array>::CompareAlmost( const PointsT<Array2>* ps ) const
{
if( !ps )
return (-2);
if(!IsDefined() && !ps->IsDefined()){
return 0;
}
if(!IsDefined()){
return -1;
}
if(!ps->IsDefined()){
return 1;
}
if( IsEmpty() && ps->IsEmpty() )
return 0;
if( IsEmpty() )
return -1;
if( ps->IsEmpty() )
return 1;
if( Size() > ps->Size() )
return 1;
if( Size() < ps->Size() )
return -1;
Point p1(true), p2(true);
for( int i = 0; i < Size(); i++ )
{
Get( i, p1);
ps->Get( i, p2 );
if( !AlmostEqual(p1, p2) )
{
if( p1 > p2 )
return 1;
if( p1 < p2 )
return -1;
}
}
return 0;
}
template<template<typename T>class Array>
bool PointsT<Array>::Adjacent( const Attribute* arg ) const
{
return false;
// for points which takes double values, we can not decide whether they are
//adjacent or not.
}
template<template<typename T>class Array>
PointsT<Array>* PointsT<Array>::Clone() const
{
return new PointsT<Array>( *this );
}
template<template<typename T>class Array>
std::ostream& PointsT<Array>::Print( std::ostream &os ) const
{
return os << *this;
}
template<template<typename T>class Array>
inline PointsT<Array>::PointsT( const int initsize ) :
StandardSpatialAttribute<2>(true),
points( initsize ),
bbox( false ),
ordered( true )
{ }
template<template<typename T>class Array>
inline PointsT<Array>::PointsT( const PointsT& ps ) :
StandardSpatialAttribute<2>(ps.IsDefined()),
points( ps.Size() ),
bbox( ps.BoundingBox() ),
ordered( ps.IsOrdered() )
{
convertDbArrays<Point>(ps.points,points);
}
template<template<typename T>class Array>
template<template<typename T2> class Array2>
inline PointsT<Array>::PointsT( const PointsT<Array2>& ps ) :
StandardSpatialAttribute<2>(ps.IsDefined()),
points( ps.Size() ),
bbox( ps.BoundingBox() ),
ordered( ps.isOrdered() )
{
convertDbArrays<Point>(ps.points,points);
}
template<template<typename T>class Array>
inline const Rectangle<2>
PointsT<Array>::BoundingBox(const Geoid* geoid /*=0*/) const
{
// no special implementation for spherical geometry required!
return bbox;
}
template<template<typename T>class Array>
inline bool PointsT<Array>::Get( const int i, Point& p ) const
{
assert( IsDefined() );
return points.Get( i, p );
}
template<template<typename T>class Array>
inline int PointsT<Array>::Size() const
{
return points.Size();
}
template<template<typename T>class Array>
inline bool PointsT<Array>::IsEmpty() const
{
return !IsDefined() || (points.Size() == 0);
}
template<template<typename T>class Array>
inline bool PointsT<Array>::IsOrdered() const
{
return ordered;
}
template<template<typename T>class Array>
inline int PointsT<Array>::NumOfFLOBs() const
{
return 1;
}
template<template<typename T>class Array>
inline bool PointsT<Array>::operator==(const Point& p) const{
if(!IsDefined() && !p.IsDefined()){
return true;
}
if(!IsDefined() || !p.IsDefined()){
return false;
}
if(Size()!=1){
return false;
}
Point p1(true);
Get(0,p1);
return AlmostEqual(p,p1);
}
template<template<typename T>class Array>
inline Flob *PointsT<Array>::GetFLOB(const int i)
{
assert( i >= 0 && i < NumOfFLOBs() );
return &points;
}
template<template<typename T>class Array>
inline size_t PointsT<Array>::Sizeof() const
{
return sizeof( *this );
}
template<template<typename T>class Array>
inline void PointsT<Array>::SelectFirst() const
{
if( IsEmpty() ){
pos = -1;
} else {
pos = 0;
}
}
template<template<typename T>class Array>
inline void PointsT<Array>::SelectNext() const
{
if( pos >= 0 && pos < Size() - 1 ) {
pos++;
} else {
pos = -1;
}
}
template<template<typename T>class Array>
inline bool PointsT<Array>::EndOfPt() const
{
return pos == -1;
}
template<template<typename T>class Array>
inline bool PointsT<Array>::GetPt(Point& p ) const
{
if( pos >= 0 && pos <= Size()-1 ){
points.Get( pos, &p );
return true;
}
return false;
}
template<template<typename T>class Array>
inline void PointsT<Array>::Resize(const int newSize){
if(newSize>Size()){
points.resize(newSize);
}
}
template<template<typename T>class Array>
inline void PointsT<Array>::TrimToSize(){
points.TrimToSize();
}
template<template<typename T2>class Array1,
template<typename T3>class Array2>
void SelectFirst_pp( const PointsT<Array1>& P1,
const PointsT<Array2>& P2,
object& obj, status& stat )
{
P1.SelectFirst();
P2.SelectFirst();
Point p1(true), p2(true);
bool gotP1 = P1.GetPt( p1 ),
gotP2 = P2.GetPt( p2 );
if( !gotP1 && !gotP2 )
{
obj = none;
stat = endboth;
}
else if( !gotP1 )
{
obj = second;
stat = endfirst;
}
else if( !gotP2 )
{
obj = first;
stat = endsecond;
}
else //both defined
{
stat = endnone;
if( p1 < p2 )
obj = first;
else if( p1 > p2 )
obj = second;
else
obj = both;
}
}
template<template<typename T1>class Array1,
template<typename T2> class Array2>
void SelectNext_pp( const PointsT<Array1>& P1,
const PointsT<Array2>& P2,
object& obj, status& stat )
{
// 1. get the current elements
Point p1(true), p2(true);
bool gotP1 = P1.GetPt( p1 ),
gotP2 = P2.GetPt( p2 );
//2. move the pointers
if( !gotP1 && !gotP2 )
{
//do nothing
}
else if( !gotP1 )
{
P2.SelectNext();
gotP2 = P2.GetPt( p2 );
}
else if( !gotP2 )
{
P1.SelectNext();
gotP1 = P1.GetPt( p1 );
}
else //both currently defined
{
if( p1 < p2 ) //then hs1 is the last output
{
P1.SelectNext();
gotP1 = P1.GetPt( p1 );
}
else if( p1 > p2 )
{
P2.SelectNext();
gotP2 = P2.GetPt( p2 );
}
else
{
P1.SelectNext();
gotP1 = P1.GetPt( p1 );
P2.SelectNext();
gotP2 = P2.GetPt( p2 );
}
}
//3. generate the outputs
if( !gotP1 && !gotP2 )
{
obj = none;
stat = endboth;
}
else if( !gotP1 )
{
obj = second;
stat = endfirst;
}
else if( !gotP2 )
{
obj = first;
stat = endsecond;
}
else //both defined
{
stat = endnone;
if( p1 < p2 )
obj = first;
else if( p1 > p2 )
obj = second;
else
obj = both;
}
}