1592 lines
40 KiB
C++
1592 lines
40 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2015, 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}}]
|
|
//paragraph [2] Filename: [{\tt \begin{center}] [\end{center}}]
|
|
|
|
[1] Implementation of the Point Sequence Classes
|
|
|
|
[2] PointSeq.cpp
|
|
|
|
\tableofcontents
|
|
|
|
\noindent
|
|
|
|
1 Introduction
|
|
|
|
This file implements and registers the type constructors ~pointseq~ and
|
|
~tpointseq~ and basic operators for these type constructors.
|
|
|
|
|
|
1.1 Type Contructors
|
|
|
|
1.1.1 ~pointseq~
|
|
|
|
A ~pointseq~ is either ~undefined~ or it is a sequence of zero or more
|
|
2-dimensional points $(x,\ y)$ with finite, real-valued coordinates $x$ and $y$.
|
|
|
|
1.1.2 ~tpointseq~
|
|
|
|
A ~tpointseq~ is either ~undefined~ or it is a sequence of zero or more
|
|
tuples $(inst,\ (x,\ y))$, each with a defined instant $inst$ and a
|
|
2-dimensional point $(x,\ y)$ with finite, real-valued coordinates $x$ and $y$.
|
|
The instants are in strictly increasing order.
|
|
|
|
|
|
1.2 Operators
|
|
|
|
1.2.1 ~isempty~
|
|
|
|
The operator $isempty : (pointseq|tpointseq) \rightarrow bool$ yields ~TRUE~, if
|
|
the sequence is ~undefined~ or contains no items, and ~FALSE~ otherwise.
|
|
|
|
1.2.2 ~no\_components~
|
|
|
|
The operator $no\_components : (pointseq|tpointseq) \rightarrow int$ determines
|
|
the number of items in the given sequence, if it is defined, and 0 otherwise.
|
|
|
|
1.2.3 ~to\_dline~
|
|
|
|
The operator $to\_dline : (pointseq|tpointseq) \rightarrow dline$ creates a
|
|
dline from a point sequence for display purposes. Each pair of successive points
|
|
yields a segment of the dline. If the sequence contains just one point, the
|
|
dline consists of single segment whose start and end are the same point.
|
|
|
|
1.2.4 ~to\_pointseq~
|
|
|
|
The operator ~to\_pointseq~ extracts a ~pointseq~ from some input object.
|
|
|
|
* The overload $to\_pointseq : mpoint [\times bool] \rightarrow pointseq$ with
|
|
$to\_pointseq(m[, ignore\_temporal\_gaps])$ is equivalent to
|
|
$to\_pointseq(to\_tpointseq(m[, ignore\_temporal\_gaps]))$ (see below).
|
|
|
|
* The overload $to\_pointseq : tpointseq \rightarrow pointseq$ computes the
|
|
spatial projection of the ~tpointseq~.
|
|
|
|
1.2.5 ~to\_tpointseq~
|
|
|
|
The operator
|
|
|
|
$to\_tpointseq : mpoint [\times bool] \rightarrow tpointseq$
|
|
|
|
with $to\_tpointseq(m[, ignore\_temporal\_gaps])$ extracts a ~tpointseq~ from a
|
|
moving point object.
|
|
|
|
If used without ~ignore\_temporal\_gaps~ or with ~ignore\_temporal\_gaps=false~,
|
|
the operator extracts a ~tpointseq~ from a moving point object as
|
|
|
|
* the start instant and point of the first unit of the moving point object
|
|
followed by
|
|
|
|
* the end instant and point of each unit whose interval contains not just a
|
|
single instant.
|
|
|
|
If there is a temporal or spatial gap between two successive units or a unit
|
|
makes a spatial move in no time, the ~tpointseq~ is ~undefined~.
|
|
|
|
If used with ~ignore\_temporal\_gaps=true~, the operator extracts a ~tpointseq~
|
|
from a moving point object as
|
|
|
|
* the start instant and point of the first unit of the moving point object
|
|
followed by
|
|
|
|
* the end instant and point of each unit whose interval contains not just a
|
|
single instant and
|
|
|
|
* the start instant and point of each unit that directly follows a temporal
|
|
gap.
|
|
|
|
If there is a spatial gap between two temporally adjacent units or a unit
|
|
makes a spatial move in no time, the ~tpointseq~ is ~undefined~.
|
|
|
|
|
|
1.2.6 ~sample\_to\_pointseq~
|
|
|
|
The operator
|
|
|
|
$sample\_to\_pointseq : tpointseq \times duration\ [\times bool\ [
|
|
\times bool]] \rightarrow pointseq$
|
|
|
|
with $sample\_to\_pointseq(P, duration, keep\_end\_point, exact\_path)$
|
|
resamples the sequence $P$ at intervals defined by $duration$ and projects it to
|
|
the spatial domain. If $keep\_end\_point$ is ~TRUE~, the original last point is
|
|
kept. If $exact\_path$ is ~TRUE~, all original points are kept, including the
|
|
last point. Both boolean parameters default to ~FALSE~.
|
|
|
|
If $duration$ is ~undefined~ or not positive, the result is ~undefined~.
|
|
|
|
1.2.7 ~sample\_to\_tpointseq~
|
|
|
|
The operator
|
|
|
|
$sample\_to\_tpointseq : tpointseq \times duration\ [\times bool\ [
|
|
\times bool]] \rightarrow tpointseq$
|
|
|
|
with $sample\_to\_tpointseq(P, duration, keep\_end\_point, exact\_path)$
|
|
resamples the sequence $P$ at intervals defined by $duration$. If
|
|
$keep\_end\_point$ is ~TRUE~, the original last point is kept. If $exact\_path$
|
|
is ~TRUE~, all original points are kept, including the last point. Both boolean
|
|
parameters default to ~FALSE~.
|
|
|
|
If $duration$ is ~undefined~ or not positive, the result is ~undefined~.
|
|
|
|
|
|
2 Includes
|
|
|
|
*/
|
|
|
|
#include "PointSeq.h"
|
|
|
|
#include "Segment.h"
|
|
#include "TrajectorySimilarity.h"
|
|
#include "VectorTypeMapUtils.h"
|
|
|
|
#include "DateTime.h" // DateTime
|
|
#include "Algebras/Spatial/DLine.h"
|
|
#include "Algebras/Spatial/Point.h"
|
|
#include "Stream.h"
|
|
#include "Algebras/Temporal/TemporalAlgebra.h" // MPoint
|
|
|
|
#include "ConstructorTemplates.h"
|
|
#include "ListUtils.h"
|
|
#include "NList.h"
|
|
#include "TypeConstructor.h"
|
|
|
|
#include <climits>
|
|
|
|
|
|
namespace tsa {
|
|
|
|
/*
|
|
3 Implementation of Class Template ~Sequence$<$T$>$~
|
|
|
|
Constructor to create a sequence from an ~NList~.
|
|
|
|
*/
|
|
template<class T>
|
|
Sequence<T>::Sequence(const NList& list)
|
|
: Attribute(/*defined*/ false), seq(0)
|
|
{
|
|
/*
|
|
The sequence may be ~undefined~. The base class ~Attribute~ and the
|
|
~DbArray$<$T$>$~ ~seq~ have been initialized accordingly.
|
|
|
|
*/
|
|
if (listutils::isSymbolUndefined(list.listExpr()))
|
|
return;
|
|
|
|
if (list.isAtom())
|
|
throw std::domain_error("List is an atom.");
|
|
|
|
SetDefined(true);
|
|
seq.resize(list.length());
|
|
|
|
/*
|
|
Iterate the list elements.
|
|
|
|
*/
|
|
T prec_item;
|
|
for (size_t i = 1; i <= list.length(); ++i) {
|
|
const NList& elem = list.elem(i);
|
|
try {
|
|
/*
|
|
Try to create an item of type ~T~ from the element. If this fails, a
|
|
~std::domain\_error~ exception is caught.
|
|
|
|
*/
|
|
const T item(elem);
|
|
/*
|
|
If this is not the first item in the list, verify that it is valid as a
|
|
successor of the preceding item. If not, a ~std::domain\_error~ exception is
|
|
caught.
|
|
|
|
*/
|
|
if (i > 1)
|
|
item.validateSequenceOrder(prec_item);
|
|
/*
|
|
Append the new item to the sequence and remember it as preceding item for the
|
|
next iteration. No exceptions happen here.
|
|
|
|
*/
|
|
append(item);
|
|
prec_item = item;
|
|
}
|
|
catch (const std::domain_error& ex) {
|
|
std::ostringstream os;
|
|
os << "Processing list element " << i << " failed: " << ex.what();
|
|
throw std::domain_error(os.str());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Copy constructor.
|
|
|
|
*/
|
|
template<class T>
|
|
Sequence<T>::Sequence(const Sequence<T>& rhs)
|
|
: Attribute(rhs.IsDefined()),
|
|
seq(rhs.GetNoComponents())
|
|
{
|
|
seq.copyFrom(rhs.seq);
|
|
}
|
|
|
|
|
|
/*
|
|
Helper for ~Sequence$<$T$>$::toDLine(DLine\&)~.
|
|
|
|
*/
|
|
template<class T>
|
|
static inline SimpleSegment makeSimpleSegment(const T& start, const T end)
|
|
{
|
|
return SimpleSegment(start.getX(), start.getY(), end.getX(), end.getY());
|
|
}
|
|
|
|
/*
|
|
Create a ~DLine~ from the sequence.
|
|
|
|
*/
|
|
template<class T>
|
|
void Sequence<T>::toDLine(DLine& dline) const
|
|
{
|
|
if(!IsDefined()){
|
|
dline.SetDefined(false);
|
|
return;
|
|
}
|
|
|
|
dline.clear();
|
|
|
|
/*
|
|
If the sequence is empty, create an empty ~DLine~.
|
|
|
|
*/
|
|
if (GetNoComponents() == 0)
|
|
return;
|
|
|
|
/*
|
|
If the sequence has only one item, create a ~DLine~ with a single segment whose
|
|
start and end point are equal.
|
|
|
|
*/
|
|
if (GetNoComponents() == 1) {
|
|
const T& item = get(0);
|
|
const SimpleSegment seg = makeSimpleSegment(item, item);
|
|
dline.append(seg);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
Otherwise iterate the pairs of successive items and create a segment for each of
|
|
them.
|
|
|
|
*/
|
|
T prev_item = get(0);
|
|
for(size_t i = 1; i < GetNoComponents(); ++i) {
|
|
const T& item = get(i);
|
|
const SimpleSegment seg = makeSimpleSegment(prev_item, item);
|
|
dline.append(seg);
|
|
prev_item = item;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Recreate the sequence from an ~MPoint~.
|
|
|
|
*/
|
|
template<class T>
|
|
void Sequence<T>::convertFrom(
|
|
const MPoint& src, const bool ignore_temporal_gaps) noexcept
|
|
{
|
|
SetDefined(false);
|
|
seq.clean();
|
|
|
|
if (!src.IsDefined())
|
|
return;
|
|
|
|
const size_t size = src.GetNoComponents();
|
|
seq.resize(size + 1);
|
|
|
|
/*
|
|
Iterare UPoints of MPoint.
|
|
|
|
*/
|
|
temporalalgebra::Interval<Instant> prec_ival =
|
|
temporalalgebra::Interval<Instant>(/*dummy*/ false);
|
|
::Point prec_p1(/*defined*/ false);
|
|
|
|
for (size_t i = 0; i < size; ++i) {
|
|
temporalalgebra::UPoint upoint;
|
|
src.Get(i, upoint);
|
|
const temporalalgebra::Interval<Instant>& ival = upoint.getTimeInterval();
|
|
const ::Point& p0 = upoint.p0;
|
|
const ::Point& p1 = upoint.p1;
|
|
|
|
if (i == 0) {
|
|
/*
|
|
Copy the start point of the first upoint.
|
|
|
|
*/
|
|
append(T(ival.start, Point(p0)));
|
|
}
|
|
else {
|
|
/*
|
|
Check for a temporal gap.
|
|
|
|
*/
|
|
if (!prec_ival.R_Adjacent(ival)) {
|
|
/*
|
|
Bail out if temporal gaps are not ignored.
|
|
|
|
*/
|
|
if (!ignore_temporal_gaps) {
|
|
seq.clean();
|
|
return;
|
|
}
|
|
/*
|
|
Otherwise also copy the start point of the first upoint after the gap.
|
|
|
|
*/
|
|
append(T(ival.start, Point(p0)));
|
|
}
|
|
else {
|
|
|
|
/*
|
|
Bail out if there is a spatial gap between temporally adjacent upoints.
|
|
|
|
*/
|
|
if (!AlmostEqual(prec_p1, p0)) {
|
|
seq.clean();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ival.start == ival.end) {
|
|
/*
|
|
The upoint contains just a single instant. Bail out if the upoint makes a
|
|
spatial move in no time. Otherwise silently ignore the end point.
|
|
|
|
*/
|
|
if (!AlmostEqual(p0, p1)) {
|
|
seq.clean();
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
The upoint's interval is not just a single instant. Therefore also copy its end
|
|
point to the sequence.
|
|
|
|
*/
|
|
append(T(ival.end, Point(p1)));
|
|
}
|
|
|
|
prec_ival = ival;
|
|
prec_p1 = p1;
|
|
}
|
|
|
|
SetDefined(true);
|
|
}
|
|
|
|
|
|
/*
|
|
Recreate the sequence from a ~TPointSeq~ with sampling.
|
|
|
|
*/
|
|
template<class T>
|
|
void Sequence<T>::sample(
|
|
const TPointSeq& src, const datetime::DateTime& duration,
|
|
const bool keep_end_point, const bool exact_path)
|
|
{
|
|
SetDefined(false);
|
|
seq.clean();
|
|
|
|
if (!src.IsDefined())
|
|
return;
|
|
|
|
SetDefined(true);
|
|
const size_t size = src.GetNoComponents();
|
|
if (size == 0)
|
|
return;
|
|
|
|
/*
|
|
Estimate number of items in the new sequence.
|
|
|
|
*/
|
|
const datetime::DateTime overall_duration =
|
|
src.get(size - 1).getInstant() - src.get(0).getInstant();
|
|
size_t estimate = (overall_duration / duration) + 1;
|
|
if (exact_path)
|
|
estimate += size - 1;
|
|
else if (keep_end_point)
|
|
++estimate;
|
|
seq.resize(estimate);
|
|
|
|
/*
|
|
Iterate source sequence.
|
|
|
|
*/
|
|
TPoint prev_pt = src.get(0);
|
|
Instant prev_inst = prev_pt.getInstant();
|
|
append(prev_pt);
|
|
Instant next_inst = prev_inst + duration;
|
|
|
|
for (size_t i = 1; i < src.GetNoComponents(); ++i) {
|
|
const TPoint& pt = src.get(i);
|
|
const Instant inst = pt.getInstant();
|
|
/*
|
|
Interpolate points between the previous and the current point, if needed.
|
|
|
|
*/
|
|
if (next_inst < inst) {
|
|
const datetime::DateTime d = inst - prev_inst;
|
|
const Point vec = pt.getPoint() - prev_pt.getPoint();
|
|
do {
|
|
const double factor = (next_inst - prev_inst) / d;
|
|
const Point new_pt = prev_pt.getPoint() + (vec * factor);
|
|
append(TPoint(next_inst, new_pt));
|
|
next_inst += duration;
|
|
} while (next_inst < inst);
|
|
}
|
|
/*
|
|
If the current point is exactly where the next point is expected, keep it.
|
|
|
|
*/
|
|
if (next_inst == inst) {
|
|
append(pt);
|
|
next_inst += duration;
|
|
}
|
|
/*
|
|
Otherwise, also keep the current point, if either the exact path shall be kept
|
|
or if it is the last point and shall be kept.
|
|
|
|
*/
|
|
else if (exact_path ||
|
|
(keep_end_point && (i == src.GetNoComponents() - 1)))
|
|
{
|
|
append(pt);
|
|
}
|
|
prev_pt = pt;
|
|
prev_inst = inst;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Get the item at position ~pos~.
|
|
|
|
*/
|
|
template<class T>
|
|
T Sequence<T>::get(const size_t pos) const
|
|
{
|
|
assert(static_cast<int>(pos) < seq.Size());
|
|
T item;
|
|
const bool success = seq.Get(pos, item);
|
|
assert(success);
|
|
return item;
|
|
}
|
|
|
|
|
|
/*
|
|
Set the item at position ~pos~.
|
|
|
|
*/
|
|
template<class T>
|
|
void Sequence<T>::set(const size_t pos, const T& item)
|
|
{
|
|
assert(static_cast<int>(pos) <= seq.Size());
|
|
const bool success = seq.Put(pos, item);
|
|
assert(success);
|
|
}
|
|
|
|
|
|
/*
|
|
Append the item to the end of the sequence.
|
|
|
|
*/
|
|
template<class T>
|
|
void Sequence<T>::append(const T& item)
|
|
{
|
|
const bool success = seq.Append(item);
|
|
assert(success);
|
|
}
|
|
|
|
|
|
/*
|
|
Create a list expression from a sequence.
|
|
|
|
*/
|
|
template<class T>
|
|
ListExpr Sequence<T>::Out(ListExpr typeInfo, Word value)
|
|
{
|
|
Sequence<T>& ps = *static_cast<Sequence<T>*>(value.addr);
|
|
if (!ps.IsDefined())
|
|
return nl->SymbolAtom(Symbol::UNDEFINED());
|
|
|
|
NList list;
|
|
for (size_t i = 0; i < ps.GetNoComponents(); ++i) {
|
|
const T& item = ps.get(i);
|
|
list.append(item.toNList());
|
|
}
|
|
|
|
return list.listExpr();
|
|
}
|
|
|
|
|
|
/*
|
|
Create a sequence from a list expression.
|
|
|
|
*/
|
|
template<class T>
|
|
Word Sequence<T>::In(
|
|
const ListExpr typeInfo, const ListExpr instance,
|
|
const int errorPos, ListExpr& errorInfo, bool& correct)
|
|
{
|
|
const NList list(instance);
|
|
Sequence<T>* ps = nullptr;
|
|
|
|
try {
|
|
/*
|
|
Let the constructor ~Sequence(const NList\& list)~ do the actual work. If it
|
|
fails, a ~std::domain\_error~ exception is caught.
|
|
|
|
*/
|
|
ps = new Sequence<T>(list);
|
|
}
|
|
catch (const std::domain_error& ex) {
|
|
correct = false;
|
|
cmsg.error() << ex.what() << std::endl;
|
|
cmsg.send();
|
|
return SetWord(Address(0));
|
|
}
|
|
|
|
correct = true;
|
|
return SetWord(ps);
|
|
}
|
|
|
|
|
|
/*
|
|
Compare two sequences as specified by ~Attribute::Compare()~.
|
|
|
|
*/
|
|
template<class T>
|
|
int Sequence<T>::Compare(const Attribute* rhs) const
|
|
{
|
|
const Sequence<T>& rps = *static_cast<const Sequence<T>*>(rhs);
|
|
|
|
/*
|
|
Handle undefined sequences. An undefined sequence is considered ~less than~ a
|
|
defined sequence. Two undefined sequences are considered equal.
|
|
|
|
*/
|
|
if (!IsDefined()) {
|
|
if (rps.IsDefined())
|
|
return -1;
|
|
return 0;
|
|
}
|
|
if (!rps.IsDefined())
|
|
return 1;
|
|
|
|
/*
|
|
Compare defined sequences. First compare them item by item until the end of the
|
|
shorter sequence. The first pair of unequal items decides, if any.
|
|
|
|
*/
|
|
size_t min_size = std::min(GetNoComponents(), rps.GetNoComponents());
|
|
for (size_t i = 0; i < min_size; ++i) {
|
|
const int cmp = get(i).compare(rps.get(i));
|
|
if (cmp != 0)
|
|
return cmp;
|
|
}
|
|
|
|
/*
|
|
Otherwise the sequences are equal, if they have the same length.
|
|
|
|
*/
|
|
if (GetNoComponents() == rps.GetNoComponents())
|
|
return 0;
|
|
|
|
/*
|
|
Otherwise the shorter sequence is considered ~less than~ the longer sequence.
|
|
|
|
*/
|
|
if (rps.GetNoComponents() > min_size)
|
|
return -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
Calculate a hash value of the sequence.
|
|
|
|
*/
|
|
template<class T>
|
|
size_t Sequence<T>::HashValue() const
|
|
{
|
|
if (!IsDefined())
|
|
return 0;
|
|
|
|
size_t hash = 0;
|
|
/*
|
|
Iterate the sequence, get the hash for each item, and XOR it with the previous
|
|
hash value rotated by one bit.
|
|
|
|
*/
|
|
for (size_t i = 0; i < GetNoComponents(); ++i)
|
|
hash = get(i).hash() ^ (hash << 1 | hash >> ((sizeof(size_t)*CHAR_BIT)-1));
|
|
|
|
return hash;
|
|
}
|
|
|
|
|
|
/*
|
|
Copy the content of ~rhs~ into ~this~, assuming that both are of the same type.
|
|
|
|
*/
|
|
template<class T>
|
|
void Sequence<T>::CopyFrom(const Attribute* rhs)
|
|
{
|
|
const Sequence<T>& rps = *static_cast<const Sequence<T>*>(rhs);
|
|
|
|
if (!rps.IsDefined()) {
|
|
SetDefined(false);
|
|
seq.clean();
|
|
return;
|
|
}
|
|
|
|
SetDefined(true);
|
|
seq.copyFrom(rps.seq);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
4 Implementation of Class ~Point~
|
|
|
|
Constructor to create an object from an ~NList~.
|
|
|
|
*/
|
|
Point::Point(const NList& list)
|
|
{
|
|
if (list.isAtom()) {
|
|
throw std::domain_error(
|
|
"Element is an atom, but a list of 2 elements is required.");
|
|
}
|
|
|
|
if (list.length() != 2) {
|
|
std::ostringstream os;
|
|
os << "Element has " << list.length() << " elements, but 2 are required.";
|
|
throw std::domain_error(os.str());
|
|
}
|
|
|
|
const NList& elem_x = list.first();
|
|
const NList& elem_y = list.second();
|
|
|
|
if (!elem_x.isReal()) {
|
|
std::ostringstream os;
|
|
os << "First element has non-real value '" << elem_x << "'.";
|
|
throw std::domain_error(os.str());
|
|
}
|
|
|
|
if (!elem_y.isReal()) {
|
|
std::ostringstream os;
|
|
os << "Second element has non-real value '" << elem_y << "'.";
|
|
throw std::domain_error(os.str());
|
|
}
|
|
|
|
x = elem_x.realval();
|
|
y = elem_y.realval();
|
|
/*
|
|
The list parser does not support non-finite real values like ~not a number~ and
|
|
~infinity~. Therefore at this point both values are finite, and the ~Point~
|
|
object is valid.
|
|
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
Constructor to create a point from a ~TPoint~ object. The coordinates are copied
|
|
and the instant is ignored.
|
|
|
|
*/
|
|
Point::Point(const TPoint& src)
|
|
: x(src.getX()),
|
|
y(src.getY())
|
|
{ }
|
|
|
|
|
|
/*
|
|
Constructor to create a point from a defined ~::Point~ object.
|
|
|
|
*/
|
|
Point::Point(const ::Point& src)
|
|
: x(src.GetX()),
|
|
y(src.GetY())
|
|
{
|
|
assert(src.IsDefined() && isValid());
|
|
}
|
|
|
|
|
|
/*
|
|
Get a string representation for display purposes.
|
|
|
|
*/
|
|
std::string Point::toString() const
|
|
{
|
|
std::ostringstream os;
|
|
os << std::setprecision(10) << "(" << x << ", " << y << ")";
|
|
return os.str();
|
|
}
|
|
|
|
|
|
/*
|
|
Get the point as a ~Point~ of the SpatialAlgebra.
|
|
|
|
*/
|
|
::Point Point::toSAPoint() const
|
|
{
|
|
return ::Point(/*defined*/ true, x, y);
|
|
}
|
|
|
|
|
|
/*
|
|
Compare ~[*]this~ to ~rhs~.
|
|
|
|
*/
|
|
int Point::compare(const Point& rhs) const
|
|
{
|
|
if (*this < rhs)
|
|
return -1;
|
|
|
|
if (*this == rhs)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
Euclidean distance between two points under consideration of a geoid.
|
|
|
|
*/
|
|
double euclideanDistance(const Point& lhs, const Point& rhs, const Geoid* geoid)
|
|
{
|
|
if (geoid == nullptr)
|
|
return euclideanDistance(lhs, rhs);
|
|
|
|
return lhs.toSAPoint().Distance(rhs.toSAPoint(), geoid);
|
|
}
|
|
|
|
|
|
/*
|
|
Squared Euclidean distance between two points under consideration of a geoid.
|
|
|
|
*/
|
|
double sqrEuclideanDistance(
|
|
const Point& lhs, const Point& rhs, const Geoid* geoid)
|
|
{
|
|
if (geoid == nullptr)
|
|
return sqrEuclideanDistance(lhs, rhs);
|
|
|
|
return pow(lhs.toSAPoint().Distance(rhs.toSAPoint(), geoid), 2);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
5 Implementation of Class ~PointSeq~
|
|
|
|
Constructor to create a ~PointSeq~ object from segment iterators.
|
|
|
|
*/
|
|
PointSeq::PointSeq(
|
|
const SegmentIt<PointSeq>& begin, const SegmentIt<PointSeq>& end)
|
|
: Sequence<Point>(/*defined*/ true)
|
|
{
|
|
if (begin == end)
|
|
return;
|
|
|
|
append(begin->getStart());
|
|
|
|
for (SegmentIt<PointSeq> it = begin; it != end; ++it)
|
|
append(it->getEnd());
|
|
}
|
|
|
|
|
|
/*
|
|
Recreate the sequence from a ~TPointSeq~.
|
|
|
|
*/
|
|
void PointSeq::convertFrom(const TPointSeq& src) noexcept
|
|
{
|
|
SetDefined(false);
|
|
seq.clean();
|
|
|
|
if (!src.IsDefined())
|
|
return;
|
|
|
|
SetDefined(true);
|
|
seq.resize(src.GetNoComponents());
|
|
for (size_t i = 0; i < src.GetNoComponents(); ++i)
|
|
append(Point(src.get(i)));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
6 Implementation of Class ~TPoint~
|
|
|
|
Constructor to create an object from an ~NList~.
|
|
|
|
*/
|
|
TPoint::TPoint(const NList& list)
|
|
: instant(datetime::instanttype)
|
|
{
|
|
if (list.isAtom())
|
|
throw std::domain_error(
|
|
"Element is an atom, but a list of 2 elements is required.");
|
|
|
|
if (list.length() != 2) {
|
|
std::ostringstream os;
|
|
os << "Element has " << list.length() << " elements, but 2 are required.";
|
|
throw std::domain_error(os.str());
|
|
}
|
|
|
|
const NList& elem_instant = list.first();
|
|
const NList& elem_point = list.second();
|
|
|
|
const bool success =
|
|
instant.ReadFrom(elem_instant.listExpr(), /*typeincluded*/ false);
|
|
if (!success) {
|
|
std::ostringstream os;
|
|
os << "First element '" << elem_instant << "' is no instant.";
|
|
throw std::domain_error(os.str());
|
|
}
|
|
|
|
if (!instant.IsDefined())
|
|
throw std::domain_error("Instant is undefined.");
|
|
|
|
try {
|
|
point = Point(elem_point);
|
|
}
|
|
catch (const std::domain_error& ex) {
|
|
std::ostringstream os;
|
|
os << "Second element is no point: " << ex.what();
|
|
throw std::domain_error(os.str());
|
|
}
|
|
/*
|
|
The ~instant~ has been checked explicitly for being defined, and the constructor
|
|
~Point(const NList\& list)~ does not support the creation of invalid (or
|
|
undefined) points. Therefore at this point the ~TPoint~ object is valid.
|
|
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
Verify that ~[*]this~ may appear as the successor of ~prec~ in a sequence of
|
|
~TPoint~s.
|
|
|
|
*/
|
|
void TPoint::validateSequenceOrder(const TPoint& prec) const
|
|
{
|
|
if (instant <= prec.instant)
|
|
throw std::domain_error(
|
|
"Instant of element is not greater than instant of preceding element.");
|
|
}
|
|
|
|
|
|
/*
|
|
Get a string representation for display purposes.
|
|
|
|
*/
|
|
std::string TPoint::toString() const
|
|
{
|
|
std::ostringstream os;
|
|
os << "(" << instant.ToString() << ", " << point.toString() << ")";
|
|
return os.str();
|
|
}
|
|
|
|
|
|
/*
|
|
Get the spatial projection of the point as a ~Point~ of the SpatialAlgebra.
|
|
|
|
*/
|
|
::Point TPoint::toSAPoint() const
|
|
{
|
|
return point.toSAPoint();
|
|
}
|
|
|
|
|
|
/*
|
|
Compare ~[*]this~ to ~rhs~.
|
|
|
|
*/
|
|
int TPoint::compare(const TPoint& rhs) const
|
|
{
|
|
if (*this < rhs)
|
|
return -1;
|
|
|
|
if (*this == rhs)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
7 Implementation of Class ~TPointSeq~
|
|
|
|
Constructor to create a ~TPointSeq~ object from segment iterators.
|
|
|
|
*/
|
|
TPointSeq::TPointSeq(
|
|
const SegmentIt<TPointSeq>& begin, const SegmentIt<TPointSeq>& end)
|
|
: Sequence<TPoint>(/*defined*/ true)
|
|
{
|
|
if (begin == end)
|
|
return;
|
|
|
|
append(begin->getStart());
|
|
|
|
for (SegmentIt<TPointSeq> it = begin; it != end; ++it)
|
|
append(it->getEnd());
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
8 Registration of Type Constructors
|
|
|
|
8.1 ~pointseq~
|
|
|
|
*/
|
|
|
|
struct PointSeqInfo : ConstructorInfo
|
|
{
|
|
PointSeqInfo()
|
|
{
|
|
name = PointSeq::BasicType();
|
|
signature = "-> " + Kind::DATA();
|
|
typeExample = PointSeq::BasicType();
|
|
listRep = "((x1 y1) (x2 y2) ... (xn yn))";
|
|
valueExample = "((0.0 0.0) (1.0 1.0) (1.0 0.0))";
|
|
remarks = "Each element of the sequence is a 2-dimensional point "
|
|
"with real coordinates.";
|
|
}
|
|
};
|
|
|
|
struct PointSeqFunctions : ConstructorFunctions<PointSeq> {
|
|
|
|
PointSeqFunctions()
|
|
{
|
|
in = PointSeq::In;
|
|
out = PointSeq::Out;
|
|
create = PointSeq::Create;
|
|
kindCheck = PointSeq::KindCheck;
|
|
}
|
|
};
|
|
|
|
PointSeqInfo psi;
|
|
PointSeqFunctions psf;
|
|
TypeConstructor pointseq(psi, psf);
|
|
|
|
void TrajectorySimilarityAlgebra::addPointSeqTC()
|
|
{
|
|
AddTypeConstructor(&pointseq);
|
|
pointseq.AssociateKind(Kind::DATA());
|
|
}
|
|
|
|
|
|
/*
|
|
8.2 ~tpointseq~
|
|
|
|
*/
|
|
struct TPointSeqInfo : ConstructorInfo
|
|
{
|
|
TPointSeqInfo()
|
|
{
|
|
name = TPointSeq::BasicType();
|
|
signature = "-> " + Kind::DATA();
|
|
typeExample = TPointSeq::BasicType();
|
|
listRep = "((i1 (x1 y1)) (i2 (x2 y2)) ... (in (xn yn)))";
|
|
valueExample = "((\"2015-12-29-00:00:00\" (0.0 0.0)) "
|
|
"(\"2015-12-29-01:00:00\" (1.0 1.0)) "
|
|
"(\"2015-12-29-02:00:00\" (1.0 0.0)))";
|
|
remarks = "Each element of the sequence is a tuple of an instant and "
|
|
"a 2-dimensional point with real coordinates. The instants "
|
|
"are in strictly increasing order.";
|
|
}
|
|
};
|
|
|
|
struct TPointSeqFunctions : ConstructorFunctions<TPointSeq> {
|
|
|
|
TPointSeqFunctions()
|
|
{
|
|
in = TPointSeq::In;
|
|
out = TPointSeq::Out;
|
|
create = TPointSeq::Create;
|
|
kindCheck = TPointSeq::KindCheck;
|
|
}
|
|
};
|
|
|
|
TPointSeqInfo tpsi;
|
|
TPointSeqFunctions tpsf;
|
|
TypeConstructor tpointseq(tpsi, tpsf);
|
|
|
|
void TrajectorySimilarityAlgebra::addTPointSeqTC()
|
|
{
|
|
AddTypeConstructor(&tpointseq);
|
|
tpointseq.AssociateKind(Kind::DATA());
|
|
}
|
|
|
|
|
|
/*
|
|
9 Registration of Operators
|
|
|
|
9.1 ~isempty~
|
|
|
|
*/
|
|
const mappings::VectorTypeMaps is_empty_maps = {
|
|
/*0*/ {{PointSeq::BasicType()}, /* -> */ {CcBool::BasicType()}},
|
|
/*1*/ {{TPointSeq::BasicType()}, /* -> */ {CcBool::BasicType()}}
|
|
};
|
|
|
|
ListExpr IsEmptyTypeMap(ListExpr args)
|
|
{ return mappings::vectorTypeMap(is_empty_maps, args); }
|
|
|
|
int IsEmptySelect(ListExpr args)
|
|
{ return mappings::vectorSelect(is_empty_maps, args); }
|
|
|
|
template<class SEQ>
|
|
int IsEmptyValueMap(
|
|
Word* args, Word& result, int /*message*/, Word& /*local*/, Supplier s)
|
|
{
|
|
const SEQ& seq = *static_cast<SEQ*>(args[0].addr);
|
|
result = qp->ResultStorage(s); // CcBool
|
|
CcBool& is_empty = *static_cast<CcBool*>(result.addr);
|
|
is_empty.Set(/*defined*/ true, seq.GetNoComponents() == 0);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping is_empty_functions[] = {
|
|
IsEmptyValueMap<PointSeq>,
|
|
IsEmptyValueMap<TPointSeq>,
|
|
nullptr
|
|
};
|
|
|
|
struct IsEmptyInfo : OperatorInfo
|
|
{
|
|
IsEmptyInfo() : OperatorInfo()
|
|
{
|
|
name = "isempty";
|
|
signature = PointSeq::BasicType() + " -> " + CcBool::BasicType();
|
|
appendSignature(
|
|
TPointSeq::BasicType() + " -> " + CcBool::BasicType());
|
|
syntax = "isempty(_)";
|
|
meaning = "Yields TRUE if the sequence is undefined or contains no items "
|
|
"and FALSE otherwise. The time complexity is O(1).";
|
|
}
|
|
};
|
|
|
|
void TrajectorySimilarityAlgebra::addIsEmptyOp()
|
|
{
|
|
AddOperator(
|
|
IsEmptyInfo(), is_empty_functions,
|
|
IsEmptySelect, IsEmptyTypeMap);
|
|
}
|
|
|
|
|
|
/*
|
|
9.2 ~no\_components~
|
|
|
|
*/
|
|
const mappings::VectorTypeMaps no_components_maps = {
|
|
/*0*/ {{PointSeq::BasicType()}, /* -> */ {CcInt::BasicType()}},
|
|
/*1*/ {{TPointSeq::BasicType()}, /* -> */ {CcInt::BasicType()}}
|
|
};
|
|
|
|
ListExpr NoComponentsTypeMap(ListExpr args)
|
|
{ return mappings::vectorTypeMap(no_components_maps, args); }
|
|
|
|
int NoComponentsSelect(ListExpr args)
|
|
{ return mappings::vectorSelect(no_components_maps, args); }
|
|
|
|
template<class SEQ>
|
|
int NoComponentsValueMap(
|
|
Word* args, Word& result, int /*message*/, Word& /*local*/, Supplier s)
|
|
{
|
|
const SEQ& seq = *static_cast<SEQ*>(args[0].addr);
|
|
result = qp->ResultStorage(s); // CcInt
|
|
CcInt& no_components = *static_cast<CcInt*>(result.addr);
|
|
no_components.Set(/*defined*/ true, seq.GetNoComponents());
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping no_components_functions[] = {
|
|
NoComponentsValueMap<PointSeq>,
|
|
NoComponentsValueMap<TPointSeq>,
|
|
nullptr
|
|
};
|
|
|
|
struct NoComponentsInfo : OperatorInfo
|
|
{
|
|
NoComponentsInfo() : OperatorInfo()
|
|
{
|
|
name = "no_components";
|
|
signature = PointSeq::BasicType() + " -> " + CcInt::BasicType();
|
|
appendSignature(
|
|
TPointSeq::BasicType() + " -> " + CcInt::BasicType());
|
|
syntax = "no_components(_)";
|
|
meaning = "Number of items in the sequence or 0, if the sequence is "
|
|
"undefined. The time complexity is O(1).";
|
|
}
|
|
};
|
|
|
|
void TrajectorySimilarityAlgebra::addNoComponentsOp()
|
|
{
|
|
AddOperator(
|
|
NoComponentsInfo(), no_components_functions,
|
|
NoComponentsSelect, NoComponentsTypeMap);
|
|
}
|
|
|
|
|
|
/*
|
|
9.3 ~to\_dline~
|
|
|
|
*/
|
|
const mappings::VectorTypeMaps to_dline_maps = {
|
|
/*0*/ {{PointSeq::BasicType()}, /* -> */ {DLine::BasicType()}},
|
|
/*1*/ {{TPointSeq::BasicType()}, /* -> */ {DLine::BasicType()}}
|
|
};
|
|
|
|
ListExpr ToDLineTypeMap(ListExpr args)
|
|
{ return mappings::vectorTypeMap(to_dline_maps, args); }
|
|
|
|
int ToDLineSelect(ListExpr args)
|
|
{ return mappings::vectorSelect(to_dline_maps, args); }
|
|
|
|
template<class T>
|
|
int ToDLineValueMap(
|
|
Word* args, Word& result, int /*message*/, Word& /*local*/, Supplier s)
|
|
{
|
|
const T& src = *static_cast<T*>(args[0].addr);
|
|
result = qp->ResultStorage(s); // DLine
|
|
DLine& dl = *static_cast<DLine*>(result.addr);
|
|
src.toDLine(dl);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping to_dline_functions[] = {
|
|
ToDLineValueMap<PointSeq>,
|
|
ToDLineValueMap<TPointSeq>,
|
|
nullptr
|
|
};
|
|
|
|
struct ToDLineInfo : OperatorInfo
|
|
{
|
|
ToDLineInfo() : OperatorInfo()
|
|
{
|
|
name = "to_dline";
|
|
signature = PointSeq::BasicType() + " -> " + DLine::BasicType();
|
|
appendSignature(
|
|
TPointSeq::BasicType() + " -> " + DLine::BasicType());
|
|
syntax = "to_dline(_)";
|
|
meaning = "Creates a dline (for display purposes) from a point sequence. "
|
|
"Each pair of successive points yields a segment of the dline. "
|
|
"If the sequence contains just one point, the dline consists "
|
|
"of single segment whose start and end are the same point.\n"
|
|
"The time complexity is O(n).";
|
|
}
|
|
};
|
|
|
|
void TrajectorySimilarityAlgebra::addToDLineOp()
|
|
{
|
|
AddOperator(
|
|
ToDLineInfo(), to_dline_functions,
|
|
ToDLineSelect, ToDLineTypeMap);
|
|
}
|
|
|
|
|
|
/*
|
|
9.4 ~to\_pointseq~
|
|
|
|
*/
|
|
const mappings::VectorTypeMaps to_pointseq_maps = {
|
|
/*0*/ {{MPoint::BasicType()}, /* -> */ {PointSeq::BasicType()}},
|
|
/*1*/ {{MPoint::BasicType(), CcBool::BasicType()},
|
|
/* -> */ {PointSeq::BasicType()}},
|
|
/*2*/ {{TPointSeq::BasicType()}, /* -> */ {PointSeq::BasicType()}}
|
|
};
|
|
|
|
ListExpr ToPointSeqTypeMap(ListExpr args)
|
|
{ return mappings::vectorTypeMap(to_pointseq_maps, args); }
|
|
|
|
int ToPointSeqSelect(ListExpr args)
|
|
{ return mappings::vectorSelect(to_pointseq_maps, args); }
|
|
|
|
template<unsigned int PARAMS=1>
|
|
int ToPointSeqValueMapMPoint(
|
|
Word* args, Word& result, int /*message*/, Word& /*local*/, Supplier s)
|
|
{
|
|
const MPoint& src = *static_cast<MPoint*>(args[0].addr);
|
|
const CcBool* cc_ignore_temporal_gaps =
|
|
(PARAMS >= 2) ? static_cast<CcBool*>(args[1].addr) : nullptr;
|
|
result = qp->ResultStorage(s); // PointSeq
|
|
PointSeq& ps = *static_cast<PointSeq*>(result.addr);
|
|
|
|
const bool ignore_temporal_gaps =
|
|
(cc_ignore_temporal_gaps && cc_ignore_temporal_gaps->IsDefined()) ?
|
|
cc_ignore_temporal_gaps->GetBoolval() : false;
|
|
|
|
ps.convertFrom(src, ignore_temporal_gaps);
|
|
return 0;
|
|
}
|
|
|
|
int ToPointSeqValueMapTPointSeq(
|
|
Word* args, Word& result, int /*message*/, Word& /*local*/, Supplier s)
|
|
{
|
|
const TPointSeq& src = *static_cast<TPointSeq*>(args[0].addr);
|
|
result = qp->ResultStorage(s); // PointSeq
|
|
PointSeq& ps = *static_cast<PointSeq*>(result.addr);
|
|
ps.convertFrom(src);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping to_pointseq_functions[] = {
|
|
ToPointSeqValueMapMPoint,
|
|
ToPointSeqValueMapMPoint</*PARAMS*/ 2>,
|
|
ToPointSeqValueMapTPointSeq,
|
|
nullptr
|
|
};
|
|
|
|
struct ToPointSeqInfo : OperatorInfo
|
|
{
|
|
ToPointSeqInfo() : OperatorInfo()
|
|
{
|
|
name = "to_pointseq";
|
|
signature = MPoint::BasicType() + " -> " + PointSeq::BasicType();
|
|
appendSignature(
|
|
MPoint::BasicType() + " x " + CcBool::BasicType() +
|
|
" -> " + PointSeq::BasicType());
|
|
appendSignature(
|
|
TPointSeq::BasicType() + " -> " + PointSeq::BasicType());
|
|
syntax = "to_pointseq(_, [ignore_temporal_gaps])";
|
|
meaning = "For an mpoint m and an optional boolean value "
|
|
"ignore_temporal_gaps this is equivalent to "
|
|
"to_pointseq(to_tpointseq(m, ignore_temporal_gaps)), but it "
|
|
"avoids a second iteration of the mpoint."
|
|
"For a tpointseq: Spatial projection of the tpointseq.\n"
|
|
"The time complexity is O(n).";
|
|
}
|
|
};
|
|
|
|
void TrajectorySimilarityAlgebra::addToPointSeqOp()
|
|
{
|
|
AddOperator(
|
|
ToPointSeqInfo(), to_pointseq_functions,
|
|
ToPointSeqSelect, ToPointSeqTypeMap);
|
|
}
|
|
|
|
|
|
/*
|
|
9.5 ~to\_tpointseq~
|
|
|
|
*/
|
|
const mappings::VectorTypeMaps to_tpointseq_maps = {
|
|
/*0*/ {{MPoint::BasicType()}, /* -> */ {TPointSeq::BasicType()}},
|
|
/*1*/ {{MPoint::BasicType(), CcBool::BasicType()},
|
|
/* -> */ {TPointSeq::BasicType()}}
|
|
};
|
|
|
|
ListExpr ToTPointSeqTypeMap(ListExpr args)
|
|
{ return mappings::vectorTypeMap(to_tpointseq_maps, args); }
|
|
|
|
int ToTPointSeqSelect(ListExpr args)
|
|
{ return mappings::vectorSelect(to_tpointseq_maps, args); }
|
|
|
|
template<unsigned int PARAMS=1>
|
|
int ToTPointSeqValueMap(
|
|
Word* args, Word& result, int /*message*/, Word& /*local*/, Supplier s)
|
|
{
|
|
const MPoint& src = *static_cast<MPoint*>(args[0].addr);
|
|
const CcBool* cc_ignore_temporal_gaps =
|
|
(PARAMS >= 2) ? static_cast<CcBool*>(args[1].addr) : nullptr;
|
|
result = qp->ResultStorage(s); // TPointSeq
|
|
TPointSeq& ps = *static_cast<TPointSeq*>(result.addr);
|
|
|
|
const bool ignore_temporal_gaps =
|
|
(cc_ignore_temporal_gaps && cc_ignore_temporal_gaps->IsDefined()) ?
|
|
cc_ignore_temporal_gaps->GetBoolval() : false;
|
|
|
|
ps.convertFrom(src, ignore_temporal_gaps);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping to_tpointseq_functions[] = {
|
|
ToTPointSeqValueMap,
|
|
ToTPointSeqValueMap</*PARAMS*/ 2>,
|
|
nullptr
|
|
};
|
|
|
|
struct ToTPointSeqInfo : OperatorInfo
|
|
{
|
|
ToTPointSeqInfo() : OperatorInfo()
|
|
{
|
|
name = "to_tpointseq";
|
|
signature = MPoint::BasicType() + " -> " + TPointSeq::BasicType();
|
|
appendSignature(
|
|
MPoint::BasicType() + " x " + CcBool::BasicType() +
|
|
" -> " + TPointSeq::BasicType());
|
|
syntax = "to_tpointseq(_, [ignore_temporal_gaps])";
|
|
meaning = "With just one parameter or with ignore_temporal_gaps=false: "
|
|
"Extracts the start instant and point of the first unit of the "
|
|
"moving point object followed by the end instant and point of "
|
|
"each unit whose interval contains not just a single instant. "
|
|
"If there is a temporal or spatial gap between two successive "
|
|
"units or a unit makes a spatial move in no time, the "
|
|
"tpointseq is undefined.\n"
|
|
"With ignore_temporal_gaps=true: Extracts the start instant "
|
|
"and point of the first unit of the moving point object "
|
|
"followed by the end instant and point of each unit whose "
|
|
"interval contains not just a single instant and the start "
|
|
"instant and point of each unit that directly follows a "
|
|
"temporal gap. If there is a spatial gap between two "
|
|
"temporally adjacent units or a unit makes a spatial move in "
|
|
"no time, the tpointseq is undefined.\n"
|
|
"The time complexity is O(n).";
|
|
}
|
|
};
|
|
|
|
void TrajectorySimilarityAlgebra::addToTPointSeqOp()
|
|
{
|
|
AddOperator(
|
|
ToTPointSeqInfo(), to_tpointseq_functions,
|
|
ToTPointSeqSelect, ToTPointSeqTypeMap);
|
|
}
|
|
|
|
|
|
/*
|
|
9.6 ~sample\_to\_pointseq~
|
|
|
|
*/
|
|
const mappings::VectorTypeMaps sample_to_pointseq_maps = {
|
|
/*0*/ {{TPointSeq::BasicType(), Duration::BasicType()},
|
|
/* -> */ {PointSeq::BasicType()}},
|
|
/*1*/ {{TPointSeq::BasicType(), Duration::BasicType(), CcBool::BasicType()},
|
|
/* -> */ {PointSeq::BasicType()}},
|
|
/*2*/ {{TPointSeq::BasicType(), Duration::BasicType(), CcBool::BasicType(),
|
|
CcBool::BasicType()}, /* -> */ {PointSeq::BasicType()}}
|
|
};
|
|
|
|
ListExpr SampleToPointSeqTypeMap(ListExpr args)
|
|
{ return mappings::vectorTypeMap(sample_to_pointseq_maps, args); }
|
|
|
|
int SampleToPointSeqSelect(ListExpr args)
|
|
{ return mappings::vectorSelect(sample_to_pointseq_maps, args); }
|
|
|
|
template<class SEQ, unsigned int PARAMS>
|
|
int SampleToPointSeqValueMap(
|
|
Word* args, Word& result, int /*message*/, Word& /*local*/, Supplier s)
|
|
{
|
|
const SEQ& src = *static_cast<SEQ*>(args[0].addr);
|
|
const datetime::DateTime& duration =
|
|
*static_cast<datetime::DateTime*>(args[1].addr);
|
|
const CcBool* cc_keep_end_point =
|
|
(PARAMS >= 3) ? static_cast<CcBool*>(args[2].addr) : nullptr;
|
|
const CcBool* cc_exact_path =
|
|
(PARAMS >= 4) ? static_cast<CcBool*>(args[3].addr) : nullptr;
|
|
result = qp->ResultStorage(s); // PointSeq
|
|
PointSeq& ps = *static_cast<PointSeq*>(result.addr);
|
|
|
|
/*
|
|
Require a defined and positive $duration$.
|
|
|
|
*/
|
|
if (!duration.IsDefined() || duration.GetType() != datetime::durationtype ||
|
|
duration.ToDouble() <= 0.0)
|
|
{
|
|
ps.SetDefined(false);
|
|
return 0;
|
|
}
|
|
|
|
const bool keep_end_point =
|
|
(cc_keep_end_point && cc_keep_end_point->IsDefined()) ?
|
|
cc_keep_end_point->GetBoolval() : false;
|
|
const bool exact_path =
|
|
(cc_exact_path && cc_exact_path->IsDefined()) ?
|
|
cc_exact_path->GetBoolval() : false;
|
|
|
|
ps.sample(src, duration, keep_end_point, exact_path);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping sample_to_pointseq_functions[] = {
|
|
SampleToPointSeqValueMap<TPointSeq, /*PARAMS*/ 2>,
|
|
SampleToPointSeqValueMap<TPointSeq, /*PARAMS*/ 3>,
|
|
SampleToPointSeqValueMap<TPointSeq, /*PARAMS*/ 4>,
|
|
nullptr
|
|
};
|
|
|
|
struct SampleToPointSeqInfo : OperatorInfo
|
|
{
|
|
SampleToPointSeqInfo() : OperatorInfo()
|
|
{
|
|
name = "sample_to_pointseq";
|
|
signature = TPointSeq::BasicType() + " x " + Duration::BasicType()
|
|
+ " -> " + PointSeq::BasicType();
|
|
appendSignature(
|
|
TPointSeq::BasicType() + " x " + Duration::BasicType()
|
|
+ " x " + CcBool::BasicType()
|
|
+ " -> " + PointSeq::BasicType());
|
|
appendSignature(
|
|
TPointSeq::BasicType() + " x " + Duration::BasicType()
|
|
+ " x " + CcBool::BasicType() + " x " + CcBool::BasicType()
|
|
+ " -> " + PointSeq::BasicType());
|
|
syntax = "sample_to_pointseq("
|
|
"seq, duration[, keep_end_point[, exact_path]])";
|
|
meaning = "Resample the sequence at intervals defined by duration and "
|
|
"project it to the spatial domain. If keep_end_point is TRUE, "
|
|
"the last point is kept. If exact_path is TRUE, all original "
|
|
"points are kept, including the last point. Both boolean "
|
|
"parameters default to FALSE.\n"
|
|
"If the duration is undefined or not positive, the result is "
|
|
"undefined.\n"
|
|
"The time complexity is O(n+m), where n is the number of "
|
|
"points in the source sequence and m is the number of points "
|
|
"in the new sequence.";
|
|
}
|
|
};
|
|
|
|
void TrajectorySimilarityAlgebra::addSampleToPointSeqOp()
|
|
{
|
|
AddOperator(
|
|
SampleToPointSeqInfo(), sample_to_pointseq_functions,
|
|
SampleToPointSeqSelect, SampleToPointSeqTypeMap);
|
|
}
|
|
|
|
|
|
/*
|
|
9.7 ~sample\_to\_tpointseq~
|
|
|
|
*/
|
|
const mappings::VectorTypeMaps sample_to_tpointseq_maps = {
|
|
/*0*/ {{TPointSeq::BasicType(), Duration::BasicType()},
|
|
/* -> */ {TPointSeq::BasicType()}},
|
|
/*1*/ {{TPointSeq::BasicType(), Duration::BasicType(), CcBool::BasicType()},
|
|
/* -> */ {TPointSeq::BasicType()}},
|
|
/*2*/ {{TPointSeq::BasicType(), Duration::BasicType(), CcBool::BasicType(),
|
|
CcBool::BasicType()}, /* -> */ {TPointSeq::BasicType()}}
|
|
};
|
|
|
|
ListExpr SampleToTPointSeqTypeMap(ListExpr args)
|
|
{ return mappings::vectorTypeMap(sample_to_tpointseq_maps, args); }
|
|
|
|
int SampleToTPointSeqSelect(ListExpr args)
|
|
{ return mappings::vectorSelect(sample_to_tpointseq_maps, args); }
|
|
|
|
template<class SEQ, unsigned int PARAMS>
|
|
int SampleToTPointSeqValueMap(
|
|
Word* args, Word& result, int /*message*/, Word& /*local*/, Supplier s)
|
|
{
|
|
const SEQ& src = *static_cast<SEQ*>(args[0].addr);
|
|
const datetime::DateTime& duration =
|
|
*static_cast<datetime::DateTime*>(args[1].addr);
|
|
const CcBool* cc_keep_end_point =
|
|
(PARAMS >= 3) ? static_cast<CcBool*>(args[2].addr) : nullptr;
|
|
const CcBool* cc_exact_path =
|
|
(PARAMS >= 4) ? static_cast<CcBool*>(args[3].addr) : nullptr;
|
|
result = qp->ResultStorage(s); // TPointSeq
|
|
TPointSeq& ps = *static_cast<TPointSeq*>(result.addr);
|
|
|
|
/*
|
|
Require a defined and positive $duration$.
|
|
|
|
*/
|
|
if (!duration.IsDefined() || duration.GetType() != datetime::durationtype ||
|
|
duration.ToDouble() <= 0.0)
|
|
{
|
|
ps.SetDefined(false);
|
|
return 0;
|
|
}
|
|
|
|
const bool keep_end_point =
|
|
(cc_keep_end_point && cc_keep_end_point->IsDefined()) ?
|
|
cc_keep_end_point->GetBoolval() : false;
|
|
const bool exact_path =
|
|
(cc_exact_path && cc_exact_path->IsDefined()) ?
|
|
cc_exact_path->GetBoolval() : false;
|
|
|
|
ps.sample(src, duration, keep_end_point, exact_path);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping sample_to_tpointseq_functions[] = {
|
|
SampleToTPointSeqValueMap<TPointSeq, /*PARAMS*/ 2>,
|
|
SampleToTPointSeqValueMap<TPointSeq, /*PARAMS*/ 3>,
|
|
SampleToTPointSeqValueMap<TPointSeq, /*PARAMS*/ 4>,
|
|
nullptr
|
|
};
|
|
|
|
struct SampleToTPointSeqInfo : OperatorInfo
|
|
{
|
|
SampleToTPointSeqInfo() : OperatorInfo()
|
|
{
|
|
name = "sample_to_tpointseq";
|
|
signature = TPointSeq::BasicType() + " x " + Duration::BasicType()
|
|
+ " -> " + TPointSeq::BasicType();
|
|
appendSignature(
|
|
TPointSeq::BasicType() + " x " + Duration::BasicType()
|
|
+ " x " + CcBool::BasicType()
|
|
+ " -> " + TPointSeq::BasicType());
|
|
appendSignature(
|
|
TPointSeq::BasicType() + " x " + Duration::BasicType()
|
|
+ " x " + CcBool::BasicType() + " x " + CcBool::BasicType()
|
|
+ " -> " + TPointSeq::BasicType());
|
|
syntax = "sample_to_tpointseq("
|
|
"seq, duration[, keep_end_point[, exact_path]])";
|
|
meaning = "Resample the sequence at intervals defined by duration. If "
|
|
"keep_end_point is TRUE, the last point is kept. If exact_path "
|
|
"is TRUE, all original points are kept, including the last "
|
|
"point. Both boolean parameters default to FALSE.\n"
|
|
"If the duration is undefined or not positive, the result is "
|
|
"undefined.\n"
|
|
"The time complexity is O(n+m), where n is the number of "
|
|
"points in the source sequence and m is the number of points "
|
|
"in the new sequence.";
|
|
}
|
|
};
|
|
|
|
void TrajectorySimilarityAlgebra::addSampleToTPointSeqOp()
|
|
{
|
|
AddOperator(
|
|
SampleToTPointSeqInfo(), sample_to_tpointseq_functions,
|
|
SampleToTPointSeqSelect, SampleToTPointSeqTypeMap);
|
|
}
|
|
|
|
} //-- namespace tsa
|