Files
secondo/Algebras/FixedMRegion/FixedMRegionAlgebra.cpp

1365 lines
39 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
----
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] Implementation of the Fixed Moving Region Algebra (FixedMRAlgebra)
September, 2016. Florian Heinz <fh@sysv.de>
[TOC]
1 Overview
This Algebra defines two new datatypes:
1.1 FixedMRegion
The ~fmregion~ represents a moving and rotating region of fixed shape.
Operations are ~atinstant~, ~inside~ (of a moving point), ~interpolate~ (for
creating an ~fmregion~ from two snapshots) and ~traversedarea~, which
calculates the exact area, which is traversed during the time interval.
1.2 CRegion
A ~cregion~ is a generalized region with curved line segments. This is the
resulttype of the ~traversedarea~ operation above, since the areas borders
are not straight lines in general. The operations (point) ~inside~ and
(region) ~intersects~ are defined on it. Additionally, the operation
~cregiontoregion~ creates an approximated classic Region from the cregion.
*/
#include "fmr/fmr_FMRegion.h"
#include "fmr/fmr_MPoint.h"
#include "fmr/fmr_RList.h"
#include "fmr/fmr_MBool.h"
#include "Algebra.h"
#include "NestedList.h"
#include "QueryProcessor.h"
#include "Algebras/Spatial/SpatialAlgebra.h"
#include "Algebras/Temporal/TemporalAlgebra.h"
#include "Algebras/MovingRegion/MovingRegionAlgebra.h"
#include "StandardTypes.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "ListUtils.h"
#include "FixedMRegionAlgebra.h"
#include <math.h>
using namespace temporalalgebra;
using namespace fmregion;
namespace fmregion {
/*
2 FMRegion type definition
An ~fmregion~ consists of a ~region~ and one or more transformation units
each describing the movement over a time interval.
2.1 List definition
(<region>(<transformation><transformation>[*]))
<region>: See SpatialAlgebra
<transformation>: (<center><v0><v><a0><a><interval>)
<center>: The center point of the rotation relative to the region
<v0>: Initial displacement of the region
<v>: Linear displacement during the time interval
<a0>: Initial rotation of the region
<a>: Rotation of the region during the time interval
<interval>: The time interval consisting of a start and end instant
Example:
(
( \_! region !\_
( \_! face 1 !\_
( \_! main cycle !\_
(190 -30)
(110 -279)
(342 -156)
(162 -216) ) ) )
( \_! transformation units !\_
( \_! transformation unit 1 !\_
(185 -164) \_! center !\_
(0 0) \_! v0 !\_
(471 482) \_! v !\_
0 \_! a0 !\_
8 \_! a !\_
\_! interval !\_
("1970-01-01-01:00:00" "1970-01-01-01:08:20" TRUE FALSE ) )
( \_! transformation unit 2 !\_
(112 -274) \_! center !\_
(655 519) \_! v0 !\_
(638 -517) \_! v !\_
8 \_! a0 !\_
5 \_! a !\_
\_! interval !\_
("1970-01-01-01:08:20" "1970-01-01-01:16:40" TRUE TRUE ) ) ) )
2.2 ~FMRegionProperty~
Describes the signature of the type constructor
*/
ListExpr FMRegionProperty() {
return (
nl->TwoElemList(
nl->FiveElemList(
nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List"),
nl->StringAtom("Remarks")
),
nl->FiveElemList(
nl->StringAtom("-> Data"),
nl->StringAtom(FMRegion::BasicType()),
nl->StringAtom("((<region>)(<transform1><transform2>...)"),
nl->StringAtom("<example too long>"),
nl->StringAtom("Type representing a moving & rotating polygon")
)
)
);
}
/*
2.3 ~OutFMRegion~
Converts the ~fmregion~ into a list representation.
(See 2.1 for the definition of the list representation)
*/
ListExpr OutFMRegion(ListExpr typeInfo, Word value) {
FMRegion *fmr = (FMRegion *) value.addr;
if (fmr->fmr != NULL) {
// RList is the interal format of the libfmr
fmr::RList rl = fmr->fmr->toRList();
// RList2NL converts RList to a Secondo NestedList
return RList2NL(rl);
} else {
return nl->Empty();
}
}
/*
2.4 ~InFMRegion~
Converts a list representation of an ~fmregion~ into a FMRegion object.
(See 2.1 for the definition of the list representation)
*/
Word InFMRegion(const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct) {
FMRegion *fmr = new FMRegion();
// Convert a Secondo NestedList to the libfmr RList
fmr::RList rl = NL2RList(instance);
// Construct a native libfmr fmregion object from the RList
fmr->fmr = new fmr::FMRegion(rl);
correct = true;
return fmr;
}
/*
2.5 ~CreateFMRegion~
Creates an empty FMRegion instance
*/
Word CreateFMRegion(const ListExpr typeInfo) {
FMRegion* fmr = new FMRegion();
return SetWord(fmr);
}
/*
2.6 ~DeleteFMRegion~
Deletes an FMRegion object
*/
void DeleteFMRegion(const ListExpr typeInfo, Word& w) {
FMRegion* fmr = (FMRegion*) w.addr;
delete fmr;
}
/*
2.7 ~CloseFMRegion~
Removes an FMRegion object from memory
*/
void CloseFMRegion(const ListExpr typeInfo, Word& w) {
FMRegion* fmr = (FMRegion*) w.addr;
delete fmr;
}
/*
2.8 ~CloneFMRegion~
Creates a deep copy of an FMRegion object
*/
Word CloneFMRegion(const ListExpr typeInfo, const Word& w) {
return SetWord(((FMRegion*) w.addr)->Clone());
}
/*
2.9 ~SizeOfFMRegion~
Returns the size of an FMRegion object
*/
int SizeOfFMRegion() {
return sizeof (FMRegion);
}
/*
2.10 ~CastFMRegion~
Casts a pointer to an FMRegion object
*/
void* CastFMRegion(void* addr) {
return (new (addr) FMRegion);
}
/*
2.11 ~CheckFMRegion~
Returns ~true~ iff a type list represents an fmregion object
*/
bool CheckFMRegion(ListExpr type, ListExpr& errorInfo) {
return (nl->IsEqual(type, FMRegion::BasicType()));
}
TypeConstructor fmregion(
FMRegion::BasicType(),
FMRegionProperty,
OutFMRegion, InFMRegion,
0, 0,
CreateFMRegion, DeleteFMRegion,
0, 0, CloseFMRegion,
CloneFMRegion, CastFMRegion,
SizeOfFMRegion, CheckFMRegion
);
/*
2.12 ~Clone~
Clone this FMRegion object, i.e. creates a deep copy
*/
FMRegion* FMRegion::Clone() const {
FMRegion *fmr = new FMRegion();
if (this->fmr != NULL) {
fmr->fmr = new fmr::FMRegion();
*(fmr->fmr) = *(this->fmr);
}
return fmr;
}
/*
2.13 ~FMRegion~ constructor
Creates an empty FMRegion object
*/
FMRegion::FMRegion() {
this->fmr = NULL;
}
/*
2.14 ~FMRegion~ destructor
Destruct an FMRegion object and the underlying libfmr object
*/
FMRegion::~FMRegion() {
if (this->fmr)
delete this->fmr;
}
/*
3 CRegion
A cregion is a new region type, which supports not only straight,
but also curved line segments of different types. The design is
held extensible to easily support other types of curves. Otherwise,
it is similar to a ~region~, which means, it consists of several faces
each optionally containing holes.
3.1 List definition
cregion: (<cface>[*])
cface: (<cycle><holecycle>[*])
cycle: (<rcurve><rcurve>[*])
In contrast to a conventional ~region~ a cycle can consist of a single
curved line segment here.
rcurve: (<xoff> <yoff> <angle> <type> <param>[*])
xoff: x offset of the startpoint
yoff: y offset of the startpoint
angle: a rotation angle
type: Type of curve
param: one or more optional parameters, which are type specific
Currently, three types of curves are defined. The parametric
functions expect ~t~ in the range of [0;1]. The result is
rotated by ~angle~ and then translated by (~xoff~,~yoff~).
T : A trochoidal line segment
Parameters: <a> <b> <toff> <rotation>
Parametric functions:
fx(t) = a[*]t[*]rot - b[*](sin(t[*]rot + toff) - sin(toff))
fy(t) = b[*](cos(t[*]rot + toff) - cos(toff))
R : A ravdoidal line segment
Parameters: <hp> <cd> <toff> <rotation>
Parametric functions:
fx(t) = hp[*](2[*]t[*]rot - sin(2[*](t[*]rot + toff)) + sin(2[*]toff)) +
cd[*] (cos (t[*]rot + toff) - cos( toff))
fy(t) = hp[*](cos(2[*](t[*]rot + toff)) - cos(2[*]toff)) +
cd[*](sin (t[*]rot + toff) - sin( toff))
S : A straight line segment
Parameters: <xd> <yd>
Parametric functions:
fx(t) = xd [*] t
fy(t) = yd [*] t
T : A trochoidal line segment
Parameters: <a> <b> <toff> <rotation>
Parametric functions:
fx(t) = a [*] t [*] rot - b [*] (sin(t [*] rot + toff) - sin(toff))
fy(t) = b [*] (cos(t [*] rot + toff) - cos(toff))
R : A ravdoidal line segment
Parameters: <hp> <cd> <toff> <rotation>
Parametric functions:
fx(t) = hp[*](2[*]t[*]rot - sin(2[*](t[*]rot + toff)) + sin(2[*]toff)) +
cd[*] (cos (t[*]rot + toff) - cos( toff))
fy(t) = hp[*](cos(2[*](t[*]rot + toff)) - cos(2[*]toff)) +
cd[*](sin (t[*]rot + toff) - sin( toff))
S : A straight line segment
Parameters: <xd> <yd>
Parametric functions:
fx(t) = xd[*]t
fy(t) = yd[*]t
T : A trochoidal line segment
Parameters: <a> <b> <toff> <rotation>
Parametric functions:
fx(t) = a[*]t[*]rot - b[*](sin(t[*]rot + toff) - sin(toff))
fy(t) = b[*](cos(t[*]rot + toff) - cos(toff))
R : A ravdoidal line segment
Parameters: <hp> <cd> <toff> <rotation>
Parametric functions:
fx(t) = hp[*](2[*]t[*]rot - sin(2[*](t[*]rot + toff)) + sin(2[*]toff)) +
cd[*] (cos (t[*]rot + toff) - cos( toff))
fy(t) = hp[*](cos(2[*](t[*]rot + toff)) - cos(2[*]toff)) +
cd[*](sin (t[*]rot + toff) - sin( toff))
S : A straight line segment
Parameters: <xd> <yd>
Parametric functions:
fx(t) = xd[*]t
fy(t) = yd[*]t
A point on the curve at time ~t~ is then calculated as:
Point(fx(t), fy(t)).rotate(<angle>) + Point(<xoff>, <yoff>)
3.2 ~CRegionProperty~
Describes the signature of the type constructor.
*/
ListExpr CRegionProperty() {
return (
nl->TwoElemList(
nl->FiveElemList(
nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List"),
nl->StringAtom("Remarks")
),
nl->FiveElemList(
nl->StringAtom("-> Data"),
nl->StringAtom(CRegion::BasicType()),
nl->StringAtom("()"),
nl->StringAtom("()"),
nl->StringAtom("A region with curved edges")
)
)
);
}
/*
3.3 ~OutCRegion~
Converts a ~cregion~ to its nested list representation.
*/
ListExpr OutCRegion(ListExpr typeInfo, Word value) {
CRegion *creg = (CRegion *) value.addr;
// Convert the libfmr region object to RList
fmr::RList rl = creg->reg->toRList();
// and then the RList to Secondo nested list representation
return RList2NL(rl);
}
/*
3.4 ~InCRegion~
Converts a ~cregion~ to its nested list representation.
*/
Word InCRegion(const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct) {
CRegion *creg = new CRegion();
// Convert the cregion nested list representation to a libfmr RList
fmr::RList rl = NL2RList(instance);
// and create an object for it.
creg->reg = new fmr::CRegion(rl);
correct = true;
return creg;
}
/*
3.5 ~CreateCRegion~
Creates an empty ~cregion~ instance.
*/
Word CreateCRegion(const ListExpr typeInfo) {
CRegion* creg = new CRegion();
return SetWord(creg);
}
/*
3.6 ~DeleteCRegion~
Removes a ~cregion~ instance.
*/
void DeleteCRegion(const ListExpr typeInfo, Word& w) {
CRegion* reg = (CRegion*) w.addr;
delete reg;
}
/*
3.7 ~CloseCRegion~
Removes a ~cregion~ instance from memory.
*/
void CloseCRegion(const ListExpr typeInfo, Word& w) {
CRegion* creg = (CRegion*) w.addr;
delete creg;
}
/*
3.7 ~CloneCRegion~
Creates a deep copy of a ~cregion~ object.
*/
Word CloneCRegion(const ListExpr typeInfo, const Word& w) {
return SetWord(((CRegion*) w.addr)->Clone());
}
/*
3.8 ~SizeOfCRegion~
Returns the size of a ~cregion~ object
*/
int SizeOfCRegion() {
return sizeof (CRegion);
}
/*
3.9 ~CastCRegion~
Casts a pointer to a ~cregion~ object
*/
void* CastCRegion(void* addr) {
return (new (addr) CRegion);
}
/*
3.10 ~CheckCRegion~
Checks if a type represents a ~cregion~ object
*/
bool CheckCRegion(ListExpr type, ListExpr& errorInfo) {
return (nl->IsEqual(type, CRegion::BasicType()));
}
TypeConstructor cregion(
CRegion::BasicType(),
CRegionProperty,
OutCRegion, InCRegion,
0, 0,
CreateCRegion, DeleteCRegion,
0, 0, CloseCRegion,
CloneCRegion, CastCRegion,
SizeOfCRegion, CheckCRegion
);
/*
3.11 ~CRegion::Clone~
Creates a clone (deep copy) of itself.
*/
CRegion* CRegion::Clone() const {
CRegion *creg = new CRegion();
creg->reg = new fmr::CRegion();
*(creg->reg) = *(this->reg);
return creg;
}
/*
3.12 ~CRegion()~
The default constructor.
*/
CRegion::CRegion() {
this->reg = NULL;
}
/*
3.13 ~CRegion destructor~
The destructor. Also deletes the underlying libfmr object.
*/
CRegion::~CRegion() {
if (this->reg)
delete this->reg;
}
/*
4 ~Operators~
Some operators for handling ~fmregion~ and ~cregion~ objects.
4.1 ~atinstant~
Calculates the projection of an ~fmregion~ to an ~iregion~ for a given instant.
Signature: fmregion x instant -> iregion
Example: query fmregion1 atinstant [const instant value "2000-01-01-01:00"]
4.1.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr atinstanttypemap(ListExpr args) {
std::string err = "fmregion x instant expected";
int len = nl->ListLength(args);
if (len != 2) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!FMRegion::checkType(nl->First(args))) {
return listutils::typeError(err + " (first arg wrong)");
}
if (!Instant::checkType(nl->Second(args))) {
return listutils::typeError(err + " (second arg wrong)");
}
return nl->SymbolAtom(temporalalgebra::IRegion::BasicType());
}
/*
4.1.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int atinstantvalmap(Word *args, Word& result,
int message, Word& local, Supplier s) {
result = qp->ResultStorage(s);
FMRegion *fmr = static_cast<FMRegion*> (args[0].addr);
Instant *it = static_cast<Instant*> (args[1].addr);
// Convert secondo instant to ms since unix epoch
double instant = (it->ToDouble()+10959)*86400000;
// Calculate the projected region in libfmr
fmr::Region fmrreg = fmr->fmr->atinstant(instant);
// and convert the result to a Secondo nested list
ListExpr regle = RList2NL(fmrreg.toRList());
// Create an IRegion from the result and return it
bool correct;
ListExpr errorInfo;
Word regp = InRegion(nl->Empty(), regle, 0, errorInfo, correct);
Region *reg = static_cast<Region*> (regp.addr);
result.setAddr(new temporalalgebra::IRegion(*it, *reg));
return 0;
}
static const std::string atinstantspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>fmregion x instant -> iregion</text--->"
"<text>_ atinstant _</text--->"
"<text>Shows the fmregion at some instant</text--->"
"<text>fmregion atinstant instant1</text---> ) )";
Operator atinstant("atinstant",
atinstantspec,
atinstantvalmap,
Operator::SimpleSelect,
atinstanttypemap
);
/*
4.2 ~setcenter~
Set the center of the rotation of this fmregion to the given point. The start
and end position of the region at the borders of the time interval will remain
unchanged, but the path will differ.
Signature: fmregion x point -> fmregion
Example: query setcenter(fmregion1, point1)
4.2.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr setcentertypemap(ListExpr args) {
std::string err = "fmregion x point expected";
int len = nl->ListLength(args);
if (len != 2) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!FMRegion::checkType(nl->First(args))) {
return listutils::typeError(err + " (wrong first arg)");
}
if (!Point::checkType(nl->Second(args))) {
return listutils::typeError(err + " (wrong second arg)");
}
return nl->SymbolAtom(FMRegion::BasicType());
}
/*
4.2.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int setcentervalmap(Word *args, Word& result,
int message, Word& local, Supplier s) {
result = qp->ResultStorage(s);
FMRegion *fmr = static_cast<FMRegion*> (args[0].addr);
Point *p = static_cast<Point*> (args[1].addr);
fmr::Point center(p->GetX(), p->GetY());
fmr::FMRegion res = *fmr->fmr;
res.setCenter(center);
// Convert the libfmr fmregion to a Secondo fmregion object and return
bool correct;
ListExpr errorInfo;
ListExpr fmle = RList2NL(res.toRList());
result = InFMRegion(nl->Empty(), fmle, 0, errorInfo, correct);
return 0;
}
static const std::string setcenterspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>fmregion x point -> fmregion</text--->"
"<text>setcenter(_,_)</text--->"
"<text>Set rotation center of fmregion</text--->"
"<text>setcenter(fmregion1, point1)</text---> ) )";
Operator setcenter("setcenter",
setcenterspec,
setcentervalmap,
Operator::SimpleSelect,
setcentertypemap
);
/*
4.3 ~intersection~
Restrict a moving point to times, when it is inside an ~fmregion~. The result
is an ~mpoint~ object, which is defined at all times, when both source objects
are defined and the ~mpoint~ is inside the ~fmregion~.
Signature: mpoint x fmregion -> mpoint
Example: query mpoint1 intersects fmregion1
4.3.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr intersectiontypemap(ListExpr args) {
std::string err = "mpoint x fmregion expected";
int len = nl->ListLength(args);
if (len != 2) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!temporalalgebra::MPoint::checkType(nl->First(args))) {
return listutils::typeError(err + " (wrong first arg)");
}
if (!FMRegion::checkType(nl->Second(args))) {
return listutils::typeError(err + " (wrong second arg)");
}
return nl->SymbolAtom(temporalalgebra::MPoint::BasicType());
}
/*
4.3.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int intersectionvalmap(Word *args, Word& result,
int message, Word& local, Supplier s) {
result = qp->ResultStorage(s);
FMRegion *fmr = static_cast<FMRegion*> (args[1].addr);
// Convert the Secondo nested list representation of the moving point
// to a libfmr MPoint object
fmr::RList mprl = NL2RList(OutMapping<MPoint, UPoint,
OutUPoint>(nl->Empty(), args[0]));
fmr::MPoint mp(mprl);
// Calculate the times, when the moving point is inside the fmregion
// and store the result in an mbool object
fmr::MPoint mp2 = mp.intersection(*fmr->fmr);
// Convert the libfmr mbool to a Secondo mbool and return it
ListExpr le = RList2NL(mp2.toRList());
bool correct;
ListExpr errorInfo;
result = InMapping<MPoint, UPoint, InUPoint>
(nl->Empty(), le, 0, errorInfo, correct);
return 0;
}
static const std::string intersectionspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>mpoint x fmregion -> mpoint</text--->"
"<text>_ intersection _</text--->"
"<text>restrict mpoint to times it is inside the fmregion</text--->"
"<text>mpoint1 intersection fmregion1</text---> ) )";
Operator intersection("intersection",
intersectionspec,
intersectionvalmap,
Operator::SimpleSelect,
intersectiontypemap
);
/*
4.4 ~inside~
Calculates the times, when a moving point is inside an ~fmregion~. The result
is an ~mbool~ object, which is defined at all times, when both source objects
are defined. The ~mbool~ is *true*, when the moving point is ~inside~ the
fmregion and *false* at all other times.
Signature: mpoint x fmregion -> mbool
Example: query mpoint1 inside fmregion1
4.4.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr insidetypemap(ListExpr args) {
std::string err = "mpoint x fmregion expected";
int len = nl->ListLength(args);
if (len != 2) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!temporalalgebra::MPoint::checkType(nl->First(args))) {
return listutils::typeError(err + " (wrong first arg)");
}
if (!FMRegion::checkType(nl->Second(args))) {
return listutils::typeError(err + " (wrong second arg)");
}
return nl->SymbolAtom(temporalalgebra::MBool::BasicType());
}
/*
4.4.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int insidevalmap(Word *args, Word& result,
int message, Word& local, Supplier s) {
result = qp->ResultStorage(s);
FMRegion *fmr = static_cast<FMRegion*> (args[1].addr);
// Convert the Secondo nested list representation of the moving point
// to a libfmr MPoint object
fmr::RList mprl = NL2RList(OutMapping<MPoint, UPoint,
OutUPoint>(nl->Empty(), args[0]));
fmr::MPoint mp(mprl);
// Calculate the times, when the moving point is inside the fmregion
// and store the result in an mbool object
fmr::MBool mb = mp.inside(*fmr->fmr);
// Convert the libfmr mbool to a Secondo mbool and return it
ListExpr le = RList2NL(mb.toRList());
bool correct;
ListExpr errorInfo;
result = InMapping<MBool, UBool, InConstTemporalUnit<CcBool, InCcBool> >
(nl->Empty(), le, 0, errorInfo, correct);
return 0;
}
static const std::string insidespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>mpoint x fmregion -> mbool</text--->"
"<text>_ inside _</text--->"
"<text>calculate times when mpoint is inside the fmregion</text--->"
"<text>mpoint1 inside fmregion1</text---> ) )";
Operator inside("inside",
insidespec,
insidevalmap,
Operator::SimpleSelect,
insidetypemap
);
/*
4.5 ~fmrinterpolate~
Try to create a ~fmregion~ from two snapshots. The shape of the region must
be identical, i.e. the second region must be a translated and rotated version
of the first one.
Signature: region x instant x region x instant -> fmregion
Example: query fmrinterpolate(region1, instant1, region2, instant2)
4.5.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr fmrinterpolatetypemap(ListExpr args) {
std::string err = "region x instant x region x instant expected";
int len = nl->ListLength(args);
if (len != 4) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!Region::checkType(nl->First(args))) {
return listutils::typeError(err + " (wrong first arg)");
}
if (!Instant::checkType(nl->Second(args))) {
return listutils::typeError(err + " (wrong second arg)");
}
if (!Region::checkType(nl->Third(args))) {
return listutils::typeError(err + " (wrong third arg)");
}
if (!Instant::checkType(nl->Fourth(args))) {
return listutils::typeError(err + " (wrong fourth arg)");
}
return nl->SymbolAtom(FMRegion::BasicType());
}
/*
4.5.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int fmrinterpolatevalmap(Word *args, Word& result,
int message, Word& local, Supplier s) {
result = qp->ResultStorage(s);
// Convert the Secondo source regions to libfmr region objects
fmr::RList sregrl = NL2RList(OutRegion(nl->Empty(), args[0]));
fmr::Region sreg(sregrl);
fmr::RList dregrl = NL2RList(OutRegion(nl->Empty(), args[2]));
fmr::Region dreg(dregrl);
Instant* ti1 = static_cast<Instant*> (args[1].addr);
Instant* ti2 = static_cast<Instant*> (args[3].addr);
#define DAYMS 86400000
// Create the interpolation interval
fmr::Interval iv((ti1->ToDouble() + 10959) * DAYMS,
(ti2->ToDouble() + 10959) * DAYMS, true, true);
// Calculate the interpolation
fmr::FMRegion fm = sreg.interpolate(dreg, iv);
// Convert the libfmr fmregion to a Secondo fmregion object and return
bool correct;
ListExpr errorInfo;
ListExpr fmle = RList2NL(fm.toRList());
result = InFMRegion(nl->Empty(), fmle, 0, errorInfo, correct);
return 0;
}
static const std::string fmrinterpolatespec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>region x instant x region x instant -> fmregion</text--->"
"<text>fmrinterpolate( _ , _ , _ , _ )</text--->"
"<text>interpolates two regions to an fmregion</text--->"
"<text>fmrinterpolate(region1, instant1, region2, instant2)</text---> ) )";
Operator fmrinterpolate("fmrinterpolate",
fmrinterpolatespec,
fmrinterpolatevalmap,
Operator::SimpleSelect,
fmrinterpolatetypemap
);
/*
4.6 ~traversedarea~
An ~fmregion~ traverses a certain area during its movement. This operator
calculates this area and returns a corresponding ~cregion~ object.
Signature: fmregion -> cregion
Example: query traversedarea(fmregion1)
4.6.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr traversedareatypemap(ListExpr args) {
std::string err = "fmregion expected";
int len = nl->ListLength(args);
if (len != 1) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!FMRegion::checkType(nl->First(args))) {
return listutils::typeError(err + " (wrong first arg)");
}
return nl->SymbolAtom(CRegion::BasicType());
}
/*
4.6.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int traversedareavalmap(Word *args, Word& result,
int message, Word& local, Supplier s) {
result = qp->ResultStorage(s);
FMRegion *fmr = static_cast<FMRegion*> (args[0].addr);
// Calculate the traversed area and store it in a libfmr region2 object
fmr::CRegion creg = fmr->fmr->traversedArea();
bool correct;
ListExpr errorInfo;
// Convert the libfmr region2 to a Secondo cregion and return it
result = InCRegion(nl->Empty(), RList2NL(creg.toRList()), 0,
errorInfo, correct);
return 0;
}
static const std::string traversedareaspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>fmregion -> cregion</text--->"
"<text>traversedarea( _ )</text--->"
"<text>calculates the traversed area of an fmregion</text--->"
"<text>traversedarea(fmregion1)</text---> ) )";
Operator traversedarea("traversedarea",
traversedareaspec,
traversedareavalmap,
Operator::SimpleSelect,
traversedareatypemap
);
/*
4.7 ~inside~
Test if a point is inside a ~cregion~
Signature: point x cregion -> bool
Example: query point([100, 100]) inside cregion1
4.7.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr insidecregiontypemap(ListExpr args) {
std::string err = "point x cregion expected";
int len = nl->ListLength(args);
if (len != 2) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!Point::checkType(nl->First(args))) {
return listutils::typeError(err + " (wrong first arg)");
}
if (!CRegion::checkType(nl->Second(args))) {
return listutils::typeError(err + " (wrong second arg)");
}
return nl->SymbolAtom(CcBool::BasicType());
}
/*
4.7.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int insidecregionvalmap(Word *args, Word& result, int message,
Word& local, Supplier s) {
result = qp->ResultStorage(s);
Point *p = static_cast<Point*> (args[0].addr);
CRegion *cr = static_cast<CRegion*> (args[1].addr);
result = new CcBool(true,
cr->reg->inside(fmr::Point(p->GetX(), p->GetY())));
return 0;
}
static const std::string insidecregionspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>point x cregion -> bool</text--->"
"<text>_ inside _</text--->"
"<text>Test if point is inside a cregion</text--->"
"<text>point1 inside cregion1</text---> ) )";
Operator insidecregion("inside",
insidecregionspec,
insidecregionvalmap,
Operator::SimpleSelect,
insidecregiontypemap
);
/*
4.8 ~intersects~
Test if a ~cregion~ intersects or overlaps with a ~region~
Signature: cregion x region -> bool
Example: query cregion1 intersects region1
4.8.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr intersectstypemap(ListExpr args) {
std::string err = "cregion x region expected";
int len = nl->ListLength(args);
if (len != 2) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!CRegion::checkType(nl->First(args))) {
return listutils::typeError(err + " (wrong first arg)");
}
if (!Region::checkType(nl->Second(args))) {
return listutils::typeError(err + " (wrong second arg)");
}
return nl->SymbolAtom(CcBool::BasicType());
}
/*
4.8.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int intersectsvalmap(Word *args, Word& result, int message,
Word& local, Supplier s) {
result = qp->ResultStorage(s);
CRegion *creg = static_cast<CRegion*> (args[0].addr);
fmr::RList regrl = NL2RList(OutRegion(nl->Empty(), args[1]));
fmr::Region reg(regrl);
result = new CcBool(true, creg->reg->intersects(reg));
return 0;
}
static const std::string intersectsspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>cregion x region -> bool</text--->"
"<text>_ intersects _</text--->"
"<text>Test if a region intersects a cregion</text--->"
"<text>cregion1 intersects region1</text---> ) )";
Operator intersects("intersects",
intersectsspec,
intersectsvalmap,
Operator::SimpleSelect,
intersectstypemap
);
/*
4.9 ~cregiontoregion~
Converts a ~cregion~ into a ~region~ by approximating the curved border with
a specified amount of straight line segments.
Signature: cregion x int -> region
Example: query cregiontoregion(cregion1, 100);
4.9.1 ~Type mapping~
Maps the source types to the result type. Only one variant is supported here.
*/
ListExpr cregiontoregiontypemap(ListExpr args) {
std::string err = "cregion x int expected";
int len = nl->ListLength(args);
if (len != 2) {
return listutils::typeError(err + " (wrong number of arguments)");
}
if (!CRegion::checkType(nl->First(args))) {
return listutils::typeError(err + " (wrong first arg)");
}
if (!CcInt::checkType(nl->Second(args))) {
return listutils::typeError(err + " (wrong second arg)");
}
return nl->SymbolAtom(Region::BasicType());
}
/*
4.9.2 ~Value mapping~
Maps a result value to the given arguments.
*/
int cregiontoregionvalmap(Word *args, Word& result, int message,
Word& local, Supplier s) {
result = qp->ResultStorage(s);
// First, convert the arguments
CRegion *creg = static_cast<CRegion*> (args[0].addr);
CcInt *nrsegs = static_cast<CcInt*> (args[1].addr);
// And create the approximated region...
fmr::Region fmrreg = creg->reg->toRegion(nrsegs->GetIntval());
// Now, union all faces of this region, since the faces may have
// overlapped in the cregion (and therefore also in the approximated
// region). This is necessary, since there is no union operation
// implemented on a cregion yet.
Region *res = NULL;
for (unsigned int i = 0; i < fmrreg.faces.size(); i++) {
fmr::Region tmp;
tmp.faces.push_back(fmrreg.faces[i]);
ListExpr regle = RList2NL(tmp.toRList());
bool correct;
ListExpr errorInfo;
Word regp = InRegion(nl->Empty(), regle, 0, errorInfo, correct);
if (!correct) {
continue;
}
Region *reg = static_cast<Region*> (regp.addr);
if (!res) {
res = reg;
} else {
Region res2(0);
res->Union(*reg, res2, NULL);
delete reg;
*res = res2;
}
}
result.setAddr(res);
return 0;
}
static const std::string cregiontoregionspec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
" (<text>cregion x int -> region</text--->"
"<text>cregiontoregion(_, _)</text--->"
"<text>Convert a cregion to an approximated region</text--->"
"<text>cregiontoregion(cregion1, 100)</text---> ) )";
Operator cregiontoregion("cregiontoregion",
cregiontoregionspec,
cregiontoregionvalmap,
Operator::SimpleSelect,
cregiontoregiontypemap
);
/*
5 ~FixedMRegionAlgebra~
Instantiation of the FixedMRegionAlgebra.
Adds the types ~fmregion~ and ~cregion~
Adds the operators ~atinstant~, ~inside~, ~fmrinterpolate~, ~traversedarea~
*/
FixedMRegionAlgebra::FixedMRegionAlgebra() : Algebra() {
AddTypeConstructor(&fmregion);
AddTypeConstructor(&cregion);
AddOperator(&atinstant);
AddOperator(&setcenter);
AddOperator(&inside);
AddOperator(&intersection);
AddOperator(&fmrinterpolate);
AddOperator(&traversedarea);
AddOperator(&intersects);
AddOperator(&insidecregion);
AddOperator(&cregiontoregion);
}
extern "C"
Algebra *
InitializeFixedMRegionAlgebra(NestedList *nlRef, QueryProcessor *qpRef) {
nl = nlRef;
qp = qpRef;
return new FixedMRegionAlgebra();
}
}
/*
6 Conversion functions
These functions convert between Secondo NestedLists and libfmr RLists.
Supported types are: List, String, Double, Bool and Symbol, which are all
existing RList types. NestedList Integers are converted to double.
Unknown types are dropped.
6.1 ~RList2NL~
Convert a libfmr RList to a Secondo NestedList.
*/
static ListExpr RList2NL(fmr::RList r) {
ListExpr ret = nl->Empty();
ListExpr cur = ret;
switch (r.getType()) {
case fmr::NL_LIST:
for (int i = 0; i < r.size(); i++) {
if (i == 0)
ret = cur = nl->OneElemList(RList2NL(r[i]));
else
cur = nl->Append(cur, RList2NL(r[i]));
}
break;
case fmr::NL_STRING:
ret = nl->StringAtom(r.getString());
break;
case fmr::NL_DOUBLE:
ret = nl->RealAtom(r.getNr());
break;
case fmr::NL_BOOL:
ret = nl->BoolAtom(r.getBool());
break;
case fmr::NL_SYM:
ret = nl->SymbolAtom(r.getSym());
break;
}
return ret;
}
/*
6.2 ~NL2RList~
Convert a Secondo NestedList to a libfmr RList.
*/
static fmr::RList NL2RList(ListExpr l) {
fmr::RList ret;
while (l != nl->Empty()) {
ListExpr i = nl->First(l);
if (nl->IsNodeType(NoAtom, i)) {
ret.append(NL2RList(i));
} else if (nl->IsNodeType(IntType, i)) {
// Convert integer to double, since there is no separate
// RList type for it
ret.append((double) nl->IntValue(i));
} else if (nl->IsNodeType(RealType, i)) {
ret.append(nl->RealValue(i));
} else if (nl->IsNodeType(BoolType, i)) {
ret.append(nl->BoolValue(i));
} else if (nl->IsNodeType(StringType, i)) {
ret.append(nl->StringValue(i));
} else if (nl->IsNodeType(SymbolType, i)) {
ret.appendSym(nl->SymbolValue(i));
}
l = nl->Rest(l);
}
return ret;
}