Files
secondo/Algebras/Periodic/LinearPointMove.cpp
2026-01-23 17:03:45 +08:00

1018 lines
26 KiB
C++

/*
3.13 ~LinearPointMove~
*/
#include <iostream>
#include <string>
#include "PeriodicTypes.h"
#include "PeriodicSupport.h"
using namespace std;
using namespace datetime;
using namespace toprel;
namespace periodic{
/*
~Constructors~
*/
LinearPointMove::LinearPointMove(){}
LinearPointMove::LinearPointMove(const LinearPointMove& source): interval(0){
Equalize(&source);
}
/*
~Destructor~
*/
LinearPointMove::~LinearPointMove(){}
/*
~Assigment operator~
*/
LinearPointMove& LinearPointMove::operator=(const LinearPointMove& source){
Equalize(&source);
return *this;
}
/*
~IsDefined~
*/
bool LinearPointMove::IsDefined()const{
return defined;
}
/*
~IsStatic~
*/
bool LinearPointMove::IsStatic()const{
return isStatic;
}
/*
~BoundingBox~
*/
PBBox LinearPointMove::BoundingBox()const{
PBBox res(startX, startY, endX, endY);
return res;
}
/*
~HashValue~
*/
size_t LinearPointMove::HashValue()const{
if(!defined) return 0;
return BoundingBox().HashValue() + interval.HashValue()+(size_t)startX;
}
/*
~Connected~
*/
bool LinearPointMove::Connected(LinearPointMove* P2){
return (endX==P2->startX) & (endY == P2->startY);
}
/*
~Constructor~
This constructor creates a new LinearPointMOve ignoring the argument.
[3] O(1)
*/
LinearPointMove::LinearPointMove(int dummy): interval(1){
__TRACE__
isStatic=true;
defined=true;
}
/*
~LinearPointMove::ToListExpr~
Converts a linear point unit into its nested list representation.
[3] O(1)
*/
ListExpr LinearPointMove::ToListExpr()const{
__TRACE__
if(defined)
return ::nl->TwoElemList(
::nl->SymbolAtom("linear"),
::nl->ThreeElemList(
interval.ToListExpr(false),
::nl->TwoElemList(
::nl->RealAtom((float)startX),
::nl->RealAtom((float)startY)),
::nl->TwoElemList(
::nl->RealAtom((float)endX),
::nl->RealAtom((float)endY))));
else
return ::nl->TwoElemList(
::nl->SymbolAtom("linear"),
::nl->TwoElemList(
interval.ToListExpr(false),
::nl->SymbolAtom("undefined")));
}
/*
~LinearPointMove::ReadFrom~
Reads the content of this LinearPointMove from value.
The return values indicates the success.
[3] O(1)
*/
bool LinearPointMove::ReadFrom(const ListExpr value){
__TRACE__
ListExpr V = value;
int L = ::nl->ListLength(V);
if(L<2 || L>3)
return false;
if(!interval.ReadFrom(::nl->First(V),false))
return false;
if(L==2){ // potentially an undefined move
if(::nl->IsEqual(::nl->Second(V),"undefined")){
defined = false;
isStatic = true;
return true;
}
return false;
}
// L == 3
ListExpr SP = ::nl->Second(V);
ListExpr EP = ::nl->Third(V);
double dv;
if(!GetNumeric(::nl->First(SP),dv)){
if(DEBUG_MODE){
cerr << __POS__ << "StartX is not a number" << endl;
}
return false;
}
startX=dv;
if(!GetNumeric(::nl->Second(SP),dv)){
if(DEBUG_MODE){
cerr << __POS__ << "StartY is not a number" << endl;
}
return false;
}
startY=dv;
if(!GetNumeric(::nl->First(EP),dv)){
if(DEBUG_MODE){
cerr << __POS__ << "EndX is not a number" << endl;
}
return false;
}
endX=dv;
if(!GetNumeric(::nl->Second(EP),dv)){
if(DEBUG_MODE){
cerr << __POS__ << "EndY is not a number" << endl;
}
return false;
}
endY= dv;
defined=true;
isStatic= (startX==endX) && (startY==endY);
return true;
}
/*
~At~
Returns the position of this linear moving point at the given time.
It's required, that the time value is contained in the interval of this
linear moving point.
[3] O(1)
*/
void LinearPointMove::At(const DateTime* duration,Point& res) const{
__TRACE__
assert(interval.Contains(duration));
assert(defined);
double delta = interval.Where(duration);
double x = startX+delta*(endX-startX);
double y = startY+delta*(endY-startY);
res.Set(x,y);
}
/*
~IsDefinedAt~
~IsDefinedAt~ checks whether this LinearPointMOve is defined
at the specified time.
[3] O(1)
*/
bool LinearPointMove::IsDefinedAt(const DateTime* duration)const{
__TRACE__
return interval.Contains(duration) && defined;
}
/*
~GetHalfSegment~
This function returns the trajectory of this LinearPointMove as an
HalfSegment. If the LinearPointMove is not defined or static,
an undefined HalfSegment is returned.
[3] O(1)
*/
bool LinearPointMove::GetHalfSegment(
const bool LeftDominatingPoint,
HalfSegment& seg)const{
__TRACE__
if(defined && !isStatic){
Point P1(true,startX,startY);
Point P2(true,endX,endY);
seg.Set(LeftDominatingPoint,P1,P2);
return true;
} else{
return false;
}
}
/*
~Intersects~
This function checks wether the trajectory of this linear
point move intersects __window__. This check is finer than the
check for intersection of the bounding boxes but can also
computed in constant time. Note that the constant time can not
ensured when another structures (like lines, points or regions)
are involved.
[3] O(1)
*/
bool LinearPointMove::Intersects(const PBBox* window)const{
__TRACE__
if(!BoundingBox().Intersects(window))
return false;
// Now, the position of all vertices of window related to the
// segment defined by this moving point is computed .
// This is done by using the formula of the directed area of the
// triangles. We use only the signum of this area.
double A,r1,r2;
bool isLeft;
double p1 = startX;
double p2 = startY;
double q1 = endX;
double q2 = endY;
window->GetVertex(0,r1,r2);
A = (r1-p1)*(r2+p2)+(q1-r1)*(q2+r2)+(p1-q1)*(p2+q2);
if(A==0)
return true;
isLeft=A<0;
for(int i=1;i<4;i++){
window->GetVertex(i,r1,r2);
A = (r1-p1)*(r2+p2)+(q1-r1)*(q2+r2)+(p1-q1)*(p2+q2);
if(A==0) return true; // a point on the segment is found
if( (A<0)!=isLeft) // a point on the other side
// of the segment is found
return true;
}
return false;
}
/*
~Split~
This function splits a moving point unit into two parts. The value of delta
has to be in the interval [0,1]. The return value states whether a rest exists.
The first part is the this instance the second part is returned by the argument
Rest. If holds delta==0 and the relative interval of this moving point is not
leftclosed, no rest exists and the result will be false. The same will be when
delta==1 and not rightclosed. This function can only used, when the interval is
bounded. But this is no restriction because a linear moving point can not have
any unbounded interval. If the closeFirst flag is true, the first part will be
rightClosed (if any rest) and the second part (rest) will be left-open. In the
other case the values are negated.
[3] O(1)
*/
bool LinearPointMove::Split(const double delta, const bool closeFirst,
LinearPointMove& Rest){
__TRACE__
assert((delta>=0) && (delta<=1));
RelInterval inter = RelInterval(0);
if(!interval.Split(delta,closeFirst,inter))
return false;
Rest.Equalize(this);
Rest.interval.Equalize(&inter);
double SplitX = startX+delta*(endX-startX);
double SplitY = startY+delta*(endY-startY);
endX = SplitX;
endY = SplitY;
Rest.startX = SplitX;
Rest.startY = SplitY;
return true;
}
/*
~SplitX~
Splits this unit into two ones at the horizontal line x==X.
If the splitLine is outside of the trajectory of this unit, nothing is
changed and false is returned.
[3] O(1)
*/
bool LinearPointMove::SplitX(const double X, const bool closeFirst,
LinearPointMove& Rest){
__TRACE__
if(startX==endX)
return false;
// start and endX are on the same side of the splitline
if( ((X-startX)<0) && ((X-endX)<0))
return false;
if( ((X-startX)>0) && ((X-endX)>0))
return false;
double delta = (X - startX)/(endX-startX);
return Split(delta,closeFirst,Rest);
}
/*
~SplitY~
Splits this unit into two ones at the vertical line y==Y.
If the splitLine is outside of the trajectory of this unit, nothing is
changed and false is returned.
[3] O(1)
*/
bool LinearPointMove::SplitY(const double Y, const bool closeFirst,
LinearPointMove& Rest){
__TRACE__
if(startY==endY)
return false;
// start and endX are on the same side of the splitline
if( ((Y-startY)<0) && ((Y-endY)<0))
return false;
if( ((Y-startY)>0) && ((Y-endY)>0))
return false;
double delta = (Y - startY)/(endY-startY);
return Split(delta,closeFirst,Rest);
}
/*
~SetUndefined~
This function makes this instance of a LinearPointMove undefined.
*/
void LinearPointMove::SetUndefined(){
__TRACE__
defined = false;
isStatic=true;
}
/*
~CanBeExtendedBy~
This function yields true iff the Intervals can summarized,
The end point of this is the startpoint pf P2 and direction and
speed are equals.
[3] O(1)
*/
bool LinearPointMove::CanBeExtendedBy(const LinearPointMove* P2)const {
__TRACE__
// check the intervals
if(!interval.CanAppended(&(P2->interval)))
return false;
// check the combinations of defined
if(!defined && !P2->defined)
return true;
if(defined && !P2->defined)
return false;
if(!defined && P2->defined)
return false;
// check Start and Endpoint
if(endX!=P2->startX)
return false;
if(endY!=P2->startY)
return false;
if(isStatic)
return P2->isStatic;
// check direction
if(abs ( ((endX-startX)*(P2->endY-P2->startY))-
((P2->endX-P2->startX)*(endY-startY)))>EPSILON)
return false;
// check speed
double L = sqrt( (startX-endX)*(startX-endX) + (startY-endY)*(startY-endY));
double P2L = sqrt( (P2->startX-P2->endX)*(P2->startX-P2->endX) +
(P2->startY-P2->endY)*(P2->startY-P2->endY));
DateTime* IL = interval.GetLength();
double T = IL->ToDouble();
delete IL;
IL = NULL;
DateTime* IL2 = ((P2->interval).GetLength());
double P2T = IL2->ToDouble();
delete IL2;
IL2 = NULL;
if( abs(L*P2T - P2L*T)>EPSILON)
return false;
return true;
}
/*
~ExtendWith~
This function concatenates the linear point moves if possible. If not, the
result will be false.
[3] O(1)
*/
bool LinearPointMove::ExtendWith(const LinearPointMove* P2){
__TRACE__
if(!CanBeExtendedBy(P2))
return false;
interval.Append(&(P2->interval));
endX = P2->endX;
endY = P2->endY;
return true;
}
/*
~Equalize~
This LinearPointMove takes its value from the argument if this
function is called.
[3] O(1)
*/
void LinearPointMove::Equalize(const LinearPointMove* P2){
__TRACE__
interval.Equalize(&(P2->interval));
startX = P2->startX;
startY = P2->startY;
endX = P2->endX;
endY = P2->endY;
isStatic = P2->isStatic;
defined = P2->defined;
}
/*
~CompareTo~
This functions implements the familiar compare function.
*/
int LinearPointMove::CompareTo(LinearPointMove* LPM){
if(!defined && !LPM->defined){
return 0;
}
if(!defined && LPM->defined){
return -1;
}
if(defined && !LPM->defined){
return 1;
}
int comp = interval.CompareTo(&(LPM->interval));
if(comp!=0){
return comp; // different intervals
}
if(startX < LPM->startX) return -1;
if(startX > LPM->startX) return 1;
if(startY < LPM->startY) return -1;
if(startY > LPM->startY) return 1;
if(endX < LPM->endX) return -1;
if(endX > LPM->endX) return 1;
if(endY < LPM->endY) return -1;
if(endY > LPM->endY) return 1;
return 0;
}
/*
~CompareSpatial~
This function compares the spatial components of this instance
and the argument, i.e. this function works like the ~CompareTo~
function but ignores the time component of the arguments.
*/
int LinearPointMove::CompareSpatial(LinearPointMove* lpm){
if(!defined && !lpm->defined)
return 0;
if(!defined && lpm->defined)
return -1;
if(defined && !lpm->defined)
return 1;
if(startX < lpm->startX) return -1;
if(startX > lpm->startX) return 1;
if(startY < lpm->startY) return -1;
if(startY > lpm->startY) return 1;
if(endX < lpm->endX) return -1;
if(endX > lpm->endX) return 1;
if(endY < lpm->endY) return -1;
if(endY > lpm->endY) return 1;
return 0;
}
/*
~ToString~
This function returns a string representation of this LinearPointsMove
*/
string LinearPointMove::ToString()const{
ostringstream res;
res << "(" << interval.ToString();
if(!defined){
res << " undefined)";
} else {
res << " (" << startX << ", " << startY <<") -> (";
res << endX << ", " << endY << "))";
}
return res.str();
}
/*
~Toprel~
This function computes the evolution of the topological relationship
between this LinearPointMove and the given static point. The caller has
to allocate enough memory in the resultbuffer, this means that the
result array has a minimum size of 3. The return value is the number of
used array slots (1..3). The resulting LinearInt9M values covers the
same relative interval as this point it does.
[3] O(1)
*/
int LinearPointMove::Toprel(const Point P, LinearInt9MMove* result)const{
// first handle undefined values
Int9M R;
if(!defined && !P.IsDefined()){
R.Set(false,false,false,false,false,false,false,false,true);
result[0].Set(R,interval);
return 1;
}
if(!defined){
R.Set(false,false,false,false,false,false,true,false,true);
result[0].Set(R,interval);
return 1;
}
if(!P.IsDefined()){
R.Set(false,false,true,false,false,false,false,false,true);
result[0].Set(R,interval);
return 1;
}
// The point describes a vertical line in the three dimensional space
// the linear moving point describes an arbitrary segment in this space
// Because the coordinates of the time dimension is equal for both lines,
// we can reduce the problem of the problem whether a point is located
// on a segment.
double dx = endX-startX;
double dy = endY-startY;
double x = P.GetX();
double y = P.GetY();
// two simple points, which are the case here, can only be equal
// or disjoint; first we define the corresponding matrices
Int9M Requal;
Requal.Set(true,false,false,false,false,false,false,false,true);
Int9M Rdisjoint;
Rdisjoint.Set(false,false,true,false,false,false,true,false,true);
// special case: moving point is static
if((dx==0 && dy==0 ) || interval.GetLength()->ToDouble()==0){
if( (x==startX) && (y==startY))
result[0].Set(Requal,interval);
else
result[0].Set(Rdisjoint,interval);
return 1;
}
// at this point we know that this point is moving
// we can conclude that in at most one timepoint the
// points are equal and they are disjoint in all other times
// point, we need a closed interval of length 0
DateTime DT(durationtype);
DT.ReadFrom(0.0);
RelInterval EmptyInt;
EmptyInt.Set(&DT,true,true);
// special case: P is startpoint of this
if( (x==startX) && (y==startY)){
if(!interval.IsLeftClosed()){
result[0].Set(Rdisjoint,interval);
return 1;
}
else{
result[0].Set(Requal,EmptyInt);
RelInterval FI;
FI.Set(interval.GetLength(),false,interval.IsRightClosed());
result[1].Set(Rdisjoint,FI);
return 2;
}
}
// special case: P is endpoint of this
if( (x==endX) && (y==endY)){
if(!interval.IsRightClosed()){
result[0].Set(Rdisjoint,interval);
return 1;
}else{
RelInterval I;
I.Set(interval.GetLength(),interval.IsLeftClosed(),false);
result[0].Set(Rdisjoint,I);
result[1].Set(Requal,EmptyInt);
return 2;
}
}
// check wether P is on the segment
if( (x-startX)*dy == (y-startY)*dx){ // on the line ?
// one of dx and dy is different to 0.0 because this case is
// aready handled above
double delta = dx==0?(y-startY)/dy:(x-startX)/dx;
if(delta<0 || delta>1){ // not on the segment
result[0].Set(Rdisjoint,interval);
return 1;
}
RelInterval I1;
RelInterval I3;
I1.Equalize(&interval);
I1.Split(delta,true,I3);
I1.Set(I1.GetLength(),I1.IsLeftClosed(),false);
DateTime ST(instanttype);
result[0].Set(Rdisjoint,I1);
result[1].Set(Requal,EmptyInt);
result[2].Set(Rdisjoint,I3);
return 3;
}else{ //point not on the segment
result[0].Set(Rdisjoint,interval);
return 1;
}
}
/*
~Toprel~
This function computes the moving topological relationship between this
LinearPointMove and a set of points given by __P__. The number of
resulting LinearInt9MMove's depends linearly on the number of the
points contained in __P__. Because the size of the result is not
constant, we use a vector for storing it.
*/
void LinearPointMove::Toprel(const Points& P,
vector<LinearInt9MMove>& Result)const{
Result.clear();
Int9M R;
if(!defined && P.IsEmpty()){
R.Set(false,false,false,false,false,false,false,false,true);
LinearInt9MMove res1(0);
res1.Set(R,interval);
Result.push_back(res1);
return;
}
if(!defined && !P.IsEmpty()){
R.Set(false,false,false,false,false,false,true,false,true);
LinearInt9MMove res1(0);
res1.Set(R,interval);
Result.push_back(res1);
return;
}
// the pmpoint is defined
if(P.IsEmpty()){
R.Set(false,false,true,false,false,false,false,false,true);
LinearInt9MMove res1(0);
res1.Set(R,interval);
Result.push_back(res1);
return;
}
// the pmpoint and the points value contain elements
assert(P.IsOrdered());
/* If the points value contains more than one point, the
9 intersection matrix will contain an 1 entry at position
interior exterior at each position. In the other case, it will
have an 1 entry either at this position or at the position
interior/interior
*/
R.Set(false,false,false,false,false,false,false,false,true);
// special case, the points value contains a single point
int size = P.Size();
if(size>1){
R.SetEI(true);
} else{
LinearInt9MMove buffer[3];
Point tP2;
P.Get(0,tP2);
int n = Toprel(tP2,buffer);
for(int i=0;i<n;i++)
Result.push_back(buffer[i]);
return;
}
// special case: point is staying
if((startX==endX && startY == endY) ||
interval.GetLength()->ToDouble()==0){
Point tmpP(startX,startY);
if(P.Contains(tmpP))
R.SetII(true);
LinearInt9MMove r1(1);
r1.Set(R,interval);
Result.push_back(r1);
return;
}
// we can scan all point in a direction to get the split point ordered
// first, we have to determine the direction;
// we create an interval of length zero
DateTime DT(durationtype);
DT.ReadFrom(0.0);
RelInterval emptyInterval;
emptyInterval.Set(&DT,true,true);
bool forward;
if(startX<endX)
forward=true;
else if(startX==endX)
forward = startY<endY;
else // startX>endX
forward = false;
Point currentPoint1(true,0,0);
Point currentPoint2(true,0,0);
RelInterval lastInterval = interval;
RelInterval newInterval;
double lastX1 = startX;
double lastY1 = startY;
double currentDelta=0;
bool done = false;
double currentX, currentY;
LinearInt9MMove currentMove;
for(int i=0;i<size && !done;i++){
if(forward){
P.Get(i,currentPoint1);
currentPoint2 = (currentPoint1);
}
else{
P.Get(size-i-1,currentPoint1);
currentPoint2 = (currentPoint1);
}
currentX = currentPoint2.GetX();
currentY = currentPoint2.GetY();
currentDelta=PointPosOnSegment(lastX1,lastY1,endX,endY,
currentX,currentY);
if(currentDelta==0){ // split at starting point
// split the interval at the begin
if(lastInterval.IsLeftClosed()){
R.SetII(true);
currentMove.Set(R,emptyInterval);
Result.push_back(currentMove);
lastInterval.Set(lastInterval.GetLength(),false,
lastInterval.IsRightClosed());
}
} else if(currentDelta>0 && currentDelta<1){ // proper split
R.SetII(false);
lastInterval.Split(currentDelta,false,newInterval);
currentMove.Set(R,lastInterval);
Result.push_back(currentMove);
R.SetII(true);
currentMove.Set(R,emptyInterval);
Result.push_back(currentMove);
newInterval.Set(newInterval.GetLength(),false,
newInterval.IsRightClosed());
lastInterval=newInterval;
lastX1 = currentX;
lastY1 = currentY;
} else if(currentDelta==1){ // split at endpoint
if(lastInterval.IsRightClosed()){
R.SetII(false);
lastInterval.Set(lastInterval.GetLength(),
lastInterval.IsLeftClosed(),false);
currentMove.Set(R,lastInterval);
Result.push_back(currentMove);
R.SetII(true);
currentMove.Set(R,emptyInterval);
Result.push_back(currentMove);
} else{
R.SetII(false);
currentMove.Set(R,lastInterval);
Result.push_back(currentMove);
}
done = true;
} else if(currentDelta>1){ // no more splitpoints are possible
R.SetII(false);
currentMove.Set(R,lastInterval);
Result.push_back(currentMove);
done=true;
}
}
if(!done) { // there is an unprocessed rest from the interval
R.SetII(false);
currentMove.Set(R,lastInterval);
Result.push_back(currentMove);
}
}
/*
~DistanceTo~
This function computes the distance of this LinearPointMove to
a fixed point. The result will be of type MovingRealUnit.If this
unit is not defined, also the reault will be not defined. In each
case, the interval of the result will be the same like the interval
of this unit.
*/
void LinearPointMove::DistanceTo(const double x, const double y,
MovingRealUnit& result)const{
if(!defined){
result.GetFrom(0,0,interval);
result.SetDefined(false);
return;
}
double startDist = sqrt( (startX-x)*(startX-x)+(startY-y)*(startY-y));
double endDist = sqrt( (endX-x)*(endX-x)+(endY-y)*(endY-y));
result.GetFrom(startDist,endDist,interval);
}
/*
~NearOverlap~
This function checks whether this unit and the argument have an nearly
common part. I.e. first is checked if the speed difference between both
units is smaller than the given epsilon value. Additionally, the distance
between both units must be smaller than the given epsilon value.
*/
bool LinearPointMove::nearOverlap(const LinearPointMove& lpm,
const double epsilonSpeed,
const double epsilonDirection,
const double epsilonSpatial) const{
if(epsilonSpeed<0 || epsilonSpatial<0 || epsilonDirection<0){
// not possible
return false;
}
double speed1 = this->Speed();
double speed2 = lpm.Speed();
if(abs(speed1-speed2)>epsilonSpeed){
return false;
}
if(speed1>epsilonSpeed || speed2>epsilonSpeed){
// check directions
double dir1 = this->Direction();
double dir2 = lpm.Direction();
if(abs(dir1-dir2)>epsilonDirection){
return false;
}
} else if(speed1<=epsilonSpeed || speed2<epsilonSpeed){
// from one arguments, the direction is not evaluable
return false;
}
// direction and speed are nearly equal, check the distance
HalfSegment hs1;
this->GetHalfSegment(true,hs1);
HalfSegment hs2;
lpm.GetHalfSegment(true,hs2);
double dist = hs2.Distance(hs2);
return dist<=epsilonSpatial;
}
/*
~Direction~
Computes the direction as angle between 0 and 360 degrees. If the point
is not moving (static or undefined), the direction will have the value -1.
*/
double LinearPointMove::Direction()const{
if(isStatic || !defined){
return -1;
}
double x = endX-startX;
double y = endY-startY;
double len = this->Length();
y = y/len;
double angle1 = asin(y);
angle1 = angle1*180.0 / M_PI;
if(y>=0 && x>=0){
return angle1;
}
if(y<0 && x>=0){ // don't allow negative values
return 360 + angle1;
}
return 180 - angle1;
}
/*
~Speed~
Computes the speed of this unit as distance / time. The optional argument is multiplied
with the time value. Basically, the speed is given in units per day.
*/
double LinearPointMove::Speed(unsigned int timefactor) const{
assert(timefactor>0);
if(!defined){
return 0;
}
double time = interval.GetLength()->ToDouble();
if(time<=0){
return 0; // no time no speed
}
time = time*(double) timefactor;
return this->Length()/time;
}
void LinearPointMove::Speed(MovingRealUnit& result) const{
if(!defined){
result.SetDefined(false);
return;
}
MRealMap map(0,0,Speed(1),false);
MovingRealUnit unit(map,interval);
unit.SetDefined(true);
result.Equalize(&unit);
}
void LinearPointMove::Direction(MovingRealUnit& result) const{
double dir = Direction();
MRealMap map(0,0,dir,false);
MovingRealUnit unit(map,interval);
unit.SetDefined(dir>=0);
result.Equalize(&unit);
}
/*
~Length~
This function computes the length of the segment given by the spatial projection
of this LinearPointMOve.
*/
double LinearPointMove::Length() const{
if(!defined){
return 0.0;
}
double distX = startX-endX;
double distY = startY-endY;
double dist = sqrt( distX*distX + distY*distY);
return dist;
}
/*
~A stream operator~
This operator can be used for debugging purposes. Its defines
a formatted output for a LinearPointMove.
*/
ostream& operator<<(ostream& os, const LinearPointMove LPM){
os << LPM.ToString();
return os;
}
} // end of namepsace periodic