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

542 lines
13 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004, 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
----
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
//[_] [\_]
1 Class DLine
*/
#ifndef DLINE_H
#define DLINE_H
#include "Attribute.h"
#include "NestedList.h"
#include "ListUtils.h"
#include "GenericTC.h"
#include "Algebras/Rectangle/RectangleAlgebra.h"
#include "HalfSegment.h"
#include "SimplePoint.h"
class SimpleSegment{
public:
SimpleSegment(){ }
SimpleSegment(const double& _x1, const double& _y1,
const double& _x2, const double& _y2):
x1(_x1), y1(_y1),x2(_x2),y2(_y2) {}
SimpleSegment(const HalfSegment& hs){
x1 = hs.GetDomPoint().GetX();
y1 = hs.GetDomPoint().GetY();
x2 = hs.GetSecPoint().GetX();
y2 = hs.GetSecPoint().GetY();
}
Rectangle<2> getBox() const{
double minD[2];
double maxD[2];
minD[0] = std::min(x1,x2);
minD[1] = std::min(y1,y2);
maxD[0] = std::max(x1,x2);
maxD[1] = std::max(y1,y1);
Rectangle<2> res(true, minD,maxD);
return res;
}
double length(){
double dx = x2-x1;
double dy = y2-y1;
return std::sqrt(dx*dx + dy*dy);
}
double x1;
double y1;
double x2;
double y2;
ListExpr ToListExpr() const{
return nl->FourElemList(
nl->RealAtom(x1),
nl->RealAtom(y1),
nl->RealAtom(x2),
nl->RealAtom(y2));
}
static bool readFirstAsNum(ListExpr& list, double& value){
ListExpr f = nl->First(list);
if(!listutils::isNumeric(f)){
return false;
}
value = listutils::getNumValue(f);
list = nl->Rest(list);
return true;
}
bool readFrom(ListExpr le){
if(!nl->HasLength(le,4)){
return false;
}
if(!readFirstAsNum(le,x1)){
return false;
}
if(!readFirstAsNum(le,y1)){
return false;
}
if(!readFirstAsNum(le,x2)){
return false;
}
if(!readFirstAsNum(le,y2)){
return false;
}
return true;
}
bool isPoint() const{
return SimplePoint(x1,y1) == SimplePoint(x2,y2);
}
static int comp(const double d1, const double d2){
if(d1<d2) return -1;
if(d1>d2) return 1;
return 0;
}
int compare(const SimpleSegment& s2){
int cmp = comp(x1,s2.x1);
if(cmp!=0) { return cmp; }
cmp = comp(y1,s2.y1);
if(cmp!=0) { return cmp; }
cmp = comp(x2,s2.x2);
if(cmp!=0) { return cmp; }
cmp = comp(y2,s2.x2);
return cmp;
}
std::ostream& print(std::ostream& os) const{
os << "(" << x1 << ", " << y1 << ") ( " << x2 << ", " << y2 << ")";
return os;
}
double Distance(const Rectangle<2>& r, const Geoid* geoid=0) const{
Point p1(true,x1,y1);
Point p2(true,x2,y2);
if(AlmostEqual(p1,p2)){
return p1.Distance(r,geoid);
} else {
HalfSegment hs(true,p1,p2);
return hs.Distance(r,geoid);
}
}
bool Intersects(const Rectangle<2>& r, const Geoid* geoid=0){
Point p1(true,x1,y1);
Point p2(true,x2,y2);
if(AlmostEqual(p1,p2)){
return r.Contains(p1.BoundingBox(),geoid);
} else {
HalfSegment hs(true,p1,p2);
return hs.Intersects(r,geoid);
}
}
void translate(const double& dx, const double& dy){
x1 += dx;
x2 += dx;
y1 += dy;
y2 += dy;
}
void rotate(const double& x, const double &y, const double& alpha){
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;
double nx1 = m00*x1 + m01*y1+m02;
y1 = m10*x1 + m11*y1+m12;
x1 = nx1;
double nx2 = m00*x2 + m01*y2+m02;
y2 = m10*x2 + m11*y2+m12;
x2 = nx2;
}
void scale(const double& sx, const double& sy){
x1 *= sx;
x2 *= sx;
y1 *= sy;
y2 *= sy;
}
};
class DLine : public StandardSpatialAttribute<2>{
public:
DLine(){}
DLine(bool def): StandardSpatialAttribute<2>(def),
segments(0), bbox(false) {}
DLine(const DLine& s): StandardSpatialAttribute<2>(s.IsDefined()),
segments(s.segments.Size()),
bbox(s.bbox){
segments.copyFrom(s.segments);
}
~DLine(){}
void clear(){
SetDefined(true);
segments.clean();
bbox.SetDefined(false);
}
void Clear(){ // renaming for compatibility
clear();
}
void append(const SimpleSegment& s) {
if(s.isPoint()){
return;
}
segments.Append(s);
bbox.Extend(s.getBox());
}
void get(size_t index, SimpleSegment& s) const{
segments.Get(index,s);
}
void set(size_t index, const SimpleSegment& s){
segments.Put(index,s);
bbox.Extend(s.getBox());
}
void resize(size_t newSize){
segments.resize(newSize);
}
ListExpr ToListExpr(ListExpr typeInfo) const {
if(!IsDefined()){
return listutils::getUndefined();
}
if(segments.Size()<1){
return nl->TheEmptyList();
}
SimpleSegment s;
segments.Get(0,s);
ListExpr res = nl->OneElemList(s.ToListExpr());
ListExpr last = res;
for(int i=1;i<segments.Size();i++){
segments.Get(i,s);
last = nl->Append(last, s.ToListExpr());
}
return res;
}
bool ReadFrom(ListExpr LE, const ListExpr typeInfo) {
SetDefined(true);
segments.clean();
bbox.SetDefined(false);
if(listutils::isSymbolUndefined(LE)){
SetDefined(false);
return true;
}
if(nl->AtomType(LE) != NoAtom){
return false;
}
SimpleSegment s;
while(!nl->IsEmpty(LE)){
if(!s.readFrom(nl->First(LE))){
segments.clean();
SetDefined(false);
return false;
}
segments.Append(s);
bbox.Extend(s.getBox());
LE = nl->Rest(LE);
}
return true;
}
// functions implementing StandardSpatialAttribute
virtual const Rectangle<2> BoundingBox(const Geoid* geoid = 0) const{
return bbox;
}
virtual double Distance(const Rectangle<2>& rect,
const Geoid* geoid=0) const{
assert(geoid==0); // not implemented case
if(!IsDefined() || !rect.IsDefined()){
return -1;
}
if(segments.Size()==0 || rect.IsEmpty()){
return -1;
}
SimpleSegment s;
segments.Get(0,s);
double dist = s.Distance(rect);
for(int i=1;i<segments.Size();i++){
segments.Get(i,s);
double d2 = s.Distance(rect);
if(d2<dist){
dist = d2;
if(AlmostEqual(dist,0)){
return 0;
}
}
}
return dist;
}
virtual bool Intersects(const Rectangle<2>& rect,
const Geoid* geoid=0 ) const{
if(!BoundingBox().Intersects(rect,geoid)){
return false;
}
if(geoid){
cout << __PRETTY_FUNCTION__ << ": Spherical geometry not implemented."
<<endl;
assert(false); // TODO: Implement spherical geometry case.
}
SimpleSegment ss;
for(int i=0;i<segments.Size();i++){
segments.Get(i,ss);
if(ss.Intersects(rect,geoid)){
return true;
}
}
return false;
}
virtual bool IsEmpty() const{
return !IsDefined() || (segments.Size()==0);
}
int Compare(const Attribute* rhs) const{
if(!IsDefined()){
return rhs->IsDefined()?-1:0;
}
if(!rhs->IsDefined()){
return 1;
}
DLine* dl = (DLine*) rhs;
if(segments.Size() < dl->segments.Size()){
return -1;
}
if(segments.Size() > dl->segments.Size()){
return 1;
}
SimpleSegment ts;
SimpleSegment ds;
for(int i=0;i<segments.Size();i++){
segments.Get(i,ts);
dl->segments.Get(i,ds);
int cmp = ts.compare(ds);
if(cmp!=0){
return cmp;
}
}
return 0;
}
int NumOfFLOBs() const{
return 1;
}
Flob* GetFLOB(int i){
return &segments;
}
bool Adjacent(const Attribute*) const {return false;}
size_t HashValue() const { return segments.Size(); }
void CopyFrom(const Attribute* arg) {
segments.clean();
if(!arg->IsDefined()){
SetDefined(false);
} else {
SetDefined(true);
}
DLine* d = (DLine*) arg;
segments.copyFrom(d->segments);
bbox = d->bbox;
}
DLine* Clone() const {
return new DLine(*this);
}
size_t Sizeof() const { return sizeof(*this); }
virtual std::ostream& Print( std::ostream& os ) const{
if(!IsDefined()){
os << "Undefined";
return os;
}
SimpleSegment s;
for(int i=0;i<segments.Size();i++){
segments.Get(i,s);
s.print(os);
os << endl;
}
return os;
}
static std::string BasicType(){
return "dline";
}
static const bool checkType(const ListExpr type){
return listutils::isSymbol(type, BasicType());
}
static ListExpr Property(){
return gentc::GenProperty("-> DATA",
BasicType(),
"(s2 s2 ...) with s_i=(x1 y1 x2 y2)",
"((14.0 18.0 16.0 15) )");
}
static bool CheckKind(ListExpr type, ListExpr& errorInfo){
return nl->IsEqual(type,BasicType());
}
int getSize() const{
return segments.Size();
}
int Size() const{
return segments.Size();
}
DLine& operator+=(const HalfSegment& hs){
if(hs.IsLeftDomPoint()){
append(SimpleSegment(hs));
}
return *this;
}
void StartBulkLoad(){}
bool EndBulkLoad() { return true; }
void Rotate(const double x, const double y, const double alpha,
DLine& result)const{
result.clear();
if(!IsDefined()){
result.SetDefined(false);
return;
}
result.resize(segments.Size());
SimpleSegment s;
for(int i=0;i<segments.Size();i++) {
segments.Get(i,s);
s.rotate(x,y,alpha);
result.append(s);
}
}
void Translate(const double x, const double y, DLine& result)const{
result.clear();
if(!IsDefined()){
result.SetDefined(false);
return;
}
result.resize(segments.Size());
SimpleSegment s;
for(int i=0;i<segments.Size();i++) {
segments.Get(i,s);
s.translate(x,y);
result.append(s);
}
}
void Scale(const double sx, const double sy, DLine& result)const{
result.clear();
if(!IsDefined()){
result.SetDefined(false);
return;
}
result.resize(segments.Size());
SimpleSegment s;
for(int i=0;i<segments.Size();i++) {
segments.Get(i,s);
s.scale(sx,sy);
if(!s.isPoint()){
result.append(s);
}
}
}
private:
DbArray<SimpleSegment> segments;
Rectangle<2> bbox;
};
#endif