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

2669 lines
60 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004-2007, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
*/
#include "Tin.h"
#include "TinPart.h"
#ifndef UNIT_TEST
#include "Algebras/Spatial/Point.h"
#include "Stream.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "Attribute.h"
#include "Algebras/Rectangle/RectangleAlgebra.h"
#include <stack>
#endif
#include <TinLogging.h>
using namespace std;
namespace tin {
#ifndef UNIT_TEST
struct tin2tuplestreamState {
Tin::triangle_iterator * itTriangles;
TupleType * tupleType;
tin2tuplestreamState() {
LOGP
itTriangles = 0;
tupleType = 0;
}
~tin2tuplestreamState() {
LOGP
if (itTriangles)
delete itTriangles;
if (tupleType)
tupleType->DeleteIfAllowed();
}
};
struct tin2tinattributestreamState {
deque<TinPart*>::iterator itParts;
deque<TinPart*>::iterator itEnd;
TupleType * tupleType;
tin2tinattributestreamState() {
LOGP
tupleType = 0;
}
~tin2tinattributestreamState() {
LOGP
if (tupleType)
tupleType->DeleteIfAllowed();
}
};
#endif
#ifndef UNIT_TEST
Tin::Tin(const TinConfiguration & conf, const bool isTemp) :
file(false,0, isTemp)
#else
Tin::Tin(const TinConfiguration & conf)
#endif
{
LOGP
if (conf.memoryState == RANDOMACCESS || conf.memoryState == GRADUALFILE
|| conf.memoryState == GRADUALTEMPORARYFILE)
throw std::runtime_error("MemoryState RANDOMACCES|GRADUAL(TEMPORARY)F"
"ILE cannot be constructed. (Tin::Tin)");
#ifndef UNIT_TEST
SmiRecord contentRec;
rtree = 0;
#endif
LOG(tinParts.size())
config = conf;
noParts = 0;
tinTypeCurrent = MANIPULATE;
constructionQueue = 0;
defined = false;
}
#ifndef UNIT_TEST
Tin::Tin(VertexContainerSet * vertices, const TinConfiguration& conf,
const bool isTemp) :
file(false,0,isTemp)
#else
Tin::Tin(VertexContainerSet * vertices, const TinConfiguration& conf)
#endif
{
LOGP
if (conf.memoryState == RANDOMACCESS || conf.memoryState == GRADUALFILE
|| conf.memoryState == GRADUALTEMPORARYFILE)
throw std::runtime_error("MemoryState RANDOMACCES|GRADUAL(TEMPORARY)FILE"
" cannot be constructed. (Tin::Tin)");
config = conf;
noParts = 0;
tinTypeCurrent = MANIPULATE;
constructionQueue = new EventQueue(this);
// to avoid horizontal stripes in fortune
// algorithm the parts are organized in columns
initColumnLayout(*vertices);
constructionQueue->doFortuneAlgorithm(vertices, true);
finishLayout();
unloadAllParts();
delete constructionQueue;
constructionQueue = 0;
defined = false;
}
Tin::~Tin() {
deque<TinPart *>::iterator it = tinParts.begin();
LOG(tinParts.size())
while (it != tinParts.end()) {
LOGP
delete (*it);
++it;
}
if (constructionQueue)
delete constructionQueue;
#ifndef UNIT_TEST
LOGP
switch (config.memoryState) {
case INMEMORY:
//for objects from disc the file
//will always stay open, thus no deletion of the tree
if (config.memoryState == INMEMORY && !file.IsOpen()) {
if (rtree)
rtree->DeleteFile();
}
if (file.IsOpen())
file.Close(true);
break;
case GRADUALFILE:
if (file.IsOpen()) //file should be open !
file.Close(true);
break;
case GRADUALTEMPORARYFILE:
LOGP
deleteFile();
if (rtree)
rtree->DeleteFile();
break;
case RANDOMACCESS:
if (file.IsOpen()) //file should be open !
file.Close(true);
break;
}
if (rtree)
delete rtree;
#endif
}
//////Analysis /////////////////////////////////////////////////
Triangle::triangleWalker Tin::getWalker(const Point_p & p) {
deque<TinPart*>::const_iterator it;
LOGP
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
if ((*it)->bbox().contains(p)) {
Point_p * dest = new Point_p[1];
dest[0] = p;
return (*it)->getWalker(dest, 1);
LOGP }
it++;
}
LOGP
throw std::runtime_error(
"Cannot walk here. Point is not part of the tin.(Tin::getWalker)");
}
VERTEX_Z Tin::atlocation(const Point_p& p) {
deque<TinPart*>::const_iterator it;
TinPart * raPart = 0;
LOGP
VERTEX_Z result = ERROR_VALUE;
#ifndef UNIT_TEST
double min[2] = { p.x, p.y };
double max[2] = { p.x, p.y };
::Rectangle<2> pointbox = ::Rectangle<2>(true, min, max);
R_TreeLeafEntry<2, uint32_t> entry;
if (rtree) {
LOGP
if (rtree->First(pointbox, entry)) {
LOGP
if (!(config.memoryState == RANDOMACCESS))
result = tinParts.at(entry.info)->atlocation(p);
else {
raPart = getPartFromDisc(entry.info);
result = raPart->atlocation(p);
delete raPart;
}
LOGP
if (result != ERROR_VALUE)
return result;
while (rtree->Next(entry)) {
if (!(config.memoryState == RANDOMACCESS))
result = tinParts.at(entry.info)->atlocation(p);
else {
raPart = getPartFromDisc(entry.info);
result = raPart->atlocation(p);
delete raPart;
}
LOGP
if (result != ERROR_VALUE)
return result;
}
}
} else {
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
if ((*it)->bbox().contains(p)) {
LOGP
result = (*it)->atlocation(p);
if (result != ERROR_VALUE)
return result;
}
it++;
}
LOGP}
#else
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
if ((*it)->bbox().contains(p)) {
LOGP
result = (*it)->atlocation(p);
if (result != ERROR_VALUE)
return result;
}
it++;
}
LOGP
#endif
LOGP
return ERROR_VALUE;
}
;
const Rectangle& Tin::bbox() const {
return features.bbox;
}
;
VERTEX_Z Tin::minimum() const {
return features.m_minValue;
}
;
VERTEX_Z Tin::maximum() const {
return features.m_maxValue;
}
;
/////////////////////////////////////////////////////////////////
///Manipulation//////////////////////////////////////////////////
void Tin::unaryOp(VERTEX_Z (*op)(VERTEX_Z z)) {
deque<TinPart*>::const_iterator it;
features.reset();
it = tinParts.begin();
while (it != tinParts.end()) {
(*it)->unaryOp(op, features);
++it;
}
}
void Tin::addPart(TinPart * p) {
LOGP
features.update(p->getFeatures());
#ifndef UNIT_TEST
LOGP
if (!rtree)
rtree = new R_Tree<2, uint32_t>(
WinUnix::getPageSize() - 2 * 2 * int(sizeof(double)), file.IsTemp());
const TinFeatures& feat = p->getFeatures();
LOGP
double min[2] = { feat.bbox.getX1(), feat.bbox.getY1() };
double max[2] = { feat.bbox.getX2(), feat.bbox.getY2() };
R_TreeLeafEntry<2, uint32_t> entry = R_TreeLeafEntry<2, uint32_t>(
::Rectangle<2>(true, min, max), noParts);
rtree->Insert(entry);
LOG_EXP(feat.print())
#endif
tinParts.push_back(p);
noParts++;
p->unloadContentData();
}
#ifndef UNIT_TEST
void Tin::unaryOp(void* function, Tin * result) {
deque<TinPart*>::const_iterator it;
TinPart* opPart;
result->tinTypeCurrent = MANIPULATE;
result->config = config;
result->config.memoryState = INMEMORY;
result->noParts = 0;
result->constructionQueue = 0;
if (this->estimateMaxSizeInMemory() * 2 > OPERATE_IN_MEMORY_THRESHOLD) {
//do not keep everything in memory
result->setMemoryStateGradual();
this->setMemoryStateGradual();
} else {
result->setMemoryState(INMEMORY);
this->setMemoryState(INMEMORY);
}
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
opPart = (*it)->clone(result);
(*it)->unloadContentData();
opPart->unaryOp(function);
result->addPart(opPart);
++it;
}
LOGP}
#endif
/*
The method setMemoryState configures the data being kept in memory.
The state INMEMORY for example loads the whole TIN in memory and
keeps it there. See the master thesis for detailed information.
*/
void Tin::setMemoryState(MemoryState st) {
LOGP
deque<TinPart *>::iterator it;
LOG("Current MemoryState:")
LOG(config.memoryState)
LOG(" ... set to ... ")
LOG(st)
if (config.memoryState == st) {
LOG(config.memoryState)
LOGP
return;
}
if (st == RANDOMACCESS)
throw std::runtime_error(
"Switch to RANDOMACCESS is not implemented.(Tin::setMemoryState)");
if (config.memoryState == GRADUALFILE && st == GRADUALTEMPORARYFILE)
throw std::runtime_error("Not reasonable.(Tin::setMemoryState)");
#ifndef UNIT_TEST
if (file.IsOpen() && st == GRADUALTEMPORARYFILE)
throw std::runtime_error("Switching to temporary file is not possible,"
" when the object comes from db!(Tin::setMemoryState)");
if (config.memoryState == RANDOMACCESS) {
switch (st) {
case GRADUALFILE:
openParts(false);
break;
case GRADUALTEMPORARYFILE:
throw std::runtime_error(
"This is not reasonable.(Tin::setMemoryState)");
break;
case INMEMORY:
openParts(true);
break;
case RANDOMACCESS:
break;
}
}
#endif
if (config.memoryState == GRADUALTEMPORARYFILE && st == INMEMORY) {
LOGP
loadAllParts();
#ifndef UNIT_TEST
deleteFile();
#endif
}
if (config.memoryState == INMEMORY && st == GRADUALTEMPORARYFILE) {
LOGP
config.memoryState = st;
#ifndef UNIT_TEST
getFile(); // this makes sure that there is a file
#endif
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
(*it)->setMemoryState(st);
++it;
}
unloadAllParts();
return;
}
if (config.memoryState == INMEMORY && st == GRADUALFILE) {
LOGP
config.memoryState = st;
#ifndef UNIT_TEST
getFile(); // this makes sure that there is a file
#endif
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
(*it)->setMemoryState(st);
++it;
}
unloadAllParts();
return;
}
config.memoryState = st;
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
(*it)->setMemoryState(st);
++it;
}
}
/////////////////////////////////////////////////////////////////
void Tin::unloadAllParts() {
deque<TinPart*>::iterator it;
if (config.memoryState != INMEMORY
&& config.memoryState != RANDOMACCESS) {
LOGP
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
//try to unload all unreferenced parts
(*it)->unloadContentData();
++it;
}
}
LOGP}
void Tin::loadAllParts() {
deque<TinPart*>::iterator it;
if (config.memoryState != INMEMORY
&& config.memoryState != RANDOMACCESS) {
LOGP
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
(*it)->loadContentData();
++it;
}
}
LOGP}
void Tin::triangulateSection(VertexContainerSet * vc) {
LOGP
if (constructionQueue) {
initColumnLayout(*vc);
constructionQueue->doFortuneAlgorithm(vc);
} else {
constructionQueue = new EventQueue(this);
initColumnLayout(*vc);
constructionQueue->doFortuneAlgorithm(vc);
}
unloadAllParts();
}
void Tin::finishTriangulation() {
LOGP
if (constructionQueue) {
VertexContainerSet *settmp = new VertexContainerSet(
VERTEX_CONTAINER_BIG_SIZE);
constructionQueue->doFortuneAlgorithm(settmp, true);
finishLayout();
delete constructionQueue;
constructionQueue = 0;
unloadAllParts();
}
}
void Tin::triangulateBulk(VertexContainerSet * vc) {
deque<TinPart*>::iterator it;
if (constructionQueue) {
initColumnLayout(*vc);
constructionQueue->doFortuneAlgorithm(vc, true);
} else {
constructionQueue = new EventQueue(this);
initColumnLayout(*vc);
constructionQueue->doFortuneAlgorithm(vc, true);
}
finishLayout();
unloadAllParts();
delete constructionQueue;
constructionQueue = 0;
}
bool Tin::canAddTriangle(const Triangle & t, std::string & msg) {
std::deque<TinPart *>::iterator it = tinParts.begin();
std::stack<TinPart *> partsToCheck;
while (it != tinParts.end()) {
if ((*it)->bbox().hasIntersection(t.bbox()))
partsToCheck.push((*it));
++it;
}
while (!partsToCheck.empty()) {
if (!partsToCheck.top()->isValidTriangle(t, msg)) {
return false;
}
partsToCheck.pop();
}
return true;
}
void Tin::addTriangle(const Vertex & v1, const Vertex & v2,
const Vertex & v3, Triangle** newtriangle) {
TinPart * newPart;
std::map<ColumnKey, TinPart *>::iterator it;
std::string msg;
it = columnMap.find(ColumnKey(v1.getX(), v1.getX()));
if (it == columnMap.end())
throw std::runtime_error(E_TIN_ADDTRIANGLE);
LOGP
Triangle t(&v1, &v2, &v3);
if (!canAddTriangle(t, msg)) {
throw std::runtime_error(msg);
}
if (!(*it).second->addTriangle_p2(v1, v2, v3, newtriangle)) {
newPart = getNewPart();
LOGP
newPart->addTriangle_p2(v1, v2, v3, newtriangle);
LOGP
finishPart((*it));
(*it).first.setNoPart(noParts - 1);
(*it).second = newPart;
(*it).second->addContentReference();
}
}
void Tin::addTriangle_p(const Vertex & v1, const Vertex & v2,
const Vertex & v3, Triangle** newtriangle) {
TinPart * newPart;
std::map<ColumnKey, TinPart *>::iterator it;
it = columnMap.find(ColumnKey(v1.getX(), v1.getX()));
if (it == columnMap.end())
throw std::runtime_error(E_TIN_ADDTRIANGLE);
if (!(*it).second->addTriangle_p(v1, v2, v3, newtriangle)) {
newPart = getNewPart();
newPart->addTriangle_p(v1, v2, v3, newtriangle);
finishPart((*it), true);
(*it).first.setNoPart(noParts - 1);
(*it).second = newPart;
(*it).second->addContentReference();
}
}
void Tin::finishLayout(bool updatePartsFeatures) {
std::map<ColumnKey, TinPart*>::iterator it;
it = columnMap.begin();
while (it != columnMap.end()) {
finishPart((*it), updatePartsFeatures);
++it;
}
columnMap.clear();
}
double Tin::calculateNoColumns(VertexContainerSet & vc) {
TIN_SIZE noTrianglesPerPartEstimate;
double noVertices, noPages, noColumns;
int noRows;
TinFeatures bbox;
bbox = vc.getFeatures();
//estimate pages
noTrianglesPerPartEstimate = TinPart::estimateNoTrianglesTotal(
config.maxSizePart);
noVertices = vc.getNoVertices();
noPages = noVertices * TRIANGLES_PER_VERTEX / noTrianglesPerPartEstimate;
//calculate columns
noColumns = std::sqrt(
(noPages * (bbox.bbox.getX2() - bbox.bbox.getX1()))
/ (bbox.bbox.getY2() - bbox.bbox.getY1()));
noRows = noPages / noColumns;
if (noRows == 0)
noColumns = noPages;
return noColumns;
}
double Tin::calculateNoRows(VertexContainerSet & vc) {
TIN_SIZE noTrianglesPerPartEstimate;
double noVertices, noPages, noColumns;
double noRows;
TinFeatures bbox;
bbox = vc.getFeatures();
//estimate pages
noTrianglesPerPartEstimate = TinPart::estimateNoTrianglesTotal(
config.maxSizePart);
noVertices = vc.getNoVertices();
noPages = noVertices * TRIANGLES_PER_VERTEX / noTrianglesPerPartEstimate;
//calculate columns
noColumns = std::sqrt(
(noPages * (bbox.bbox.getX2() - bbox.bbox.getX1()))
/ (bbox.bbox.getY2() - bbox.bbox.getY1()));
noRows = noPages / noColumns;
return noRows;
}
void Tin::finishPart(std::pair<const ColumnKey, TinPart*>& partpair,
bool updatePartFeat) {
if (updatePartFeat)
partpair.second->updateFeatures();
features.update(partpair.second->getFeatures());
#ifndef UNIT_TEST
if (!rtree)
rtree = new R_Tree<2, uint32_t>(
WinUnix::getPageSize() - 2 * 2 * int(sizeof(double)), file.IsTemp());
const TinFeatures& feat = partpair.second->getFeatures();
double min[2] = { feat.bbox.getX1(), feat.bbox.getY1() };
double max[2] = { feat.bbox.getX2(), feat.bbox.getY2() };
R_TreeLeafEntry<2, uint32_t> entry = R_TreeLeafEntry<2, uint32_t>(
::Rectangle<2>(true, min, max), partpair.first.getNoPart());
rtree->Insert(entry);
#endif
partpair.second->deleteContentReference();
partpair.second->unloadContentData();
}
/*
The method initSimpleLayout initializes a single infinite column
as layout for the distribution of new triangles among the TinParts.
*/
void Tin::initSimpleLayout() {
std::pair<ColumnKey, TinPart *> p;
//clear existing Layout
finishLayout();
//just one column with a new part
p.first = ColumnKey(-std::numeric_limits<VERTEX_COORDINATE>::max(),
std::numeric_limits<VERTEX_COORDINATE>::max(), noParts);
p.second = getNewPart();
p.second->addContentReference();
columnMap.insert(p);
}
/*
The method initColumnLayout initializes several columns as layout.
The columns try to achieve squared TinParts. This is done by
the evaluation of the VertexContainerSet vc an the configuration.
*/
void Tin::initColumnLayout(VertexContainerSet & vc) {
TinFeatures bbox;
std::stack<std::pair<const ColumnKey, TinPart *> > incompleteParts;
std::pair<ColumnKey, TinPart *> p;
std::map<ColumnKey, TinPart *>::reverse_iterator ritMap;
int columnWidth;
double noColumns;
int inoColumns;
TinPart * newPart;
uint32_t noPart;
if (columnMap.size()) {
ritMap = columnMap.rbegin();
// rescue current incomplete parts for the next row
while (ritMap != columnMap.rend()) {
incompleteParts.push((*ritMap));
++ritMap;
}
columnMap.clear();
}
vc.updateXindexAndFeatures();
noColumns = calculateNoColumns(vc);
if ((int) noColumns > 1)
columnWidth = vc.getNoVertices() / noColumns;
else {
//just one column
if (!incompleteParts.empty()) {
p = incompleteParts.top();
p.first = ColumnKey(-std::numeric_limits<VERTEX_COORDINATE>::max(),
std::numeric_limits<VERTEX_COORDINATE>::max(), p.first.getNoPart());
incompleteParts.pop();
} else {
p.first = ColumnKey(-std::numeric_limits<VERTEX_COORDINATE>::max(),
std::numeric_limits<VERTEX_COORDINATE>::max(), noParts);
p.second = getNewPart();
p.second->addContentReference();
}
columnMap.insert(p);
while (!incompleteParts.empty()) {
finishPart(incompleteParts.top(), true);
incompleteParts.pop();
}
return;
}
inoColumns = noColumns;
for (int i = 0; i < inoColumns; i++) {
if (!incompleteParts.empty()) {
p = incompleteParts.top();
noPart = p.first.getNoPart();
newPart = p.second;
incompleteParts.pop();
} else {
noPart = noParts;
newPart = getNewPart();
newPart->addContentReference();
}
//due to rounding take care of the last row to contain surplus
if (i == (inoColumns - 1))
p.first = ColumnKey(vc.getVertexByXIndex(i * columnWidth)->getX(),
std::numeric_limits<VERTEX_COORDINATE>::max(), noPart);
else if (i == 0)
p.first = ColumnKey(-std::numeric_limits<VERTEX_COORDINATE>::max(),
vc.getVertexByXIndex((i + 1) * columnWidth)->getX(), noPart);
else
p.first = ColumnKey(vc.getVertexByXIndex(i * columnWidth)->getX(),
vc.getVertexByXIndex((i + 1) * columnWidth)->getX(), noPart);
p.second = newPart;
columnMap.insert(p);
}
while (!incompleteParts.empty()) {
finishPart(incompleteParts.top(), true);
incompleteParts.pop();
}
}
void Tin::saveSTLFile(std::ostream& os) {
triangle_iterator it = begin();
deque<TinPart*>::iterator itp;
TIN_SIZE notriangles = 0;
itp = tinParts.begin();
while (itp != tinParts.end()) {
notriangles += (*itp)->getNoTriangles();
itp++;
}
char* buffer = new char[80 + 4 + notriangles * (4 * 12 + 2)];
uint32_t offset;
memset(buffer, 0, 80);
memcpy(buffer + 80, &notriangles, 4);
offset = 84;
while ((*it)) {
(*it)->putSTLbinaryRepresentation(buffer, offset);
it++;
}
os.write(buffer, 80 + 4 + notriangles * (4 * 12 + 2));
delete[] buffer;
}
void Tin::print(std::ostream& os) {
deque<TinPart *>::iterator it = tinParts.begin();
os << "TinType-------\n";
os << "Configuration: \n";
os << " Page size: " << config.maxSizePart << " part type "
<< config.abstractType << "\n";
features.print(os);
os << "Parts:--------------------------------------------\n";
while (it != tinParts.end()) {
os << *(*it);
++it;
}
}
bool Tin::hasTriangle(Vertex& v1, Vertex& v2, Vertex& v3) {
deque<TinPart*>::const_iterator it;
LOGP
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
if ((*it)->bbox().contains(Point_p(v1.getX(), v1.getY()))
&& (*it)->bbox().contains(Point_p(v2.getX(), v2.getY()))
&& (*it)->bbox().contains(Point_p(v3.getX(), v3.getY()))) {
LOGP
if ((*it)->hasTriangle(v1, v2, v3))
return true;
}
it++;
}
LOGP
return false;
}
Tin * Tin::clone() const {
deque<TinPart*>::const_iterator it;
TinPart * copyPart;
LOGP
TinConfiguration conf = config;
conf.memoryState = INMEMORY;
Tin * tt = new Tin(conf, file.IsTemp());
#ifndef UNIT_TEST
if (this->estimateMaxSizeInMemory() * 2 < OPERATE_IN_MEMORY_THRESHOLD) {
LOGP
tt->setMemoryState(INMEMORY);
const_cast<Tin*>(this)->setMemoryState(INMEMORY);
} else {
LOGP
tt->setMemoryState(GRADUALTEMPORARYFILE);
const_cast<Tin*>(this)->setMemoryStateGradual();
}
#endif
LOGP
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
copyPart = (*it)->clone(tt);
tt->addPart(copyPart);
(*it)->unloadContentData();
++it;
}
LOGP
return tt;
}
void Tin::cloneTin(Tin * result) const {
deque<TinPart*>::const_iterator it;
LOGP
#ifndef UNIT_TEST
if (this->estimateMaxSizeInMemory() * 2 < OPERATE_IN_MEMORY_THRESHOLD) {
LOGP
result->setMemoryState(INMEMORY);
const_cast<Tin*>(this)->setMemoryState(INMEMORY);
} else {
LOGP
result->setMemoryStateGradual();
const_cast<Tin*>(this)->setMemoryStateGradual();
}
#endif
LOGP
result->config.maxSizePart = config.maxSizePart;
it = tinParts.begin();
while (it != tinParts.end()) {
LOGP
result->addPart((*it)->clone(result));
(*it)->unloadContentData();
++it;
}
LOGP}
#ifndef UNIT_TEST
void Tin::setMemoryStateGradual() {
if (config.memoryState == GRADUALFILE
|| config.memoryState == GRADUALTEMPORARYFILE)
return;
if (file.IsOpen()) {
setMemoryState(GRADUALFILE);
return;
} else {
setMemoryState(GRADUALTEMPORARYFILE);
return;
}
}
ListExpr Tin::tin2stlfile_tm(ListExpr args) {
if (nl->ListLength(args) != 2)
return NList::typeError("Expected two arguments. (tin2stl)");
if (!nl->IsAtom(nl->First(args))
|| nl->SymbolValue(nl->First(args)) != Tin::BasicType())
return NList::typeError(
"The first argument is wrong. Expected a tin. (tin2stl)");
if (!nl->IsAtom(nl->Second(args))
|| nl->SymbolValue(nl->Second(args)) != CcString::BasicType())
return NList::typeError(
"The second argument is wrong. Expected a string. (tin2stl)");
return nl->SymbolAtom(CcBool::BasicType());
}
int Tin::tin2stlfile_vm(Word* args, Word& result, int message, Word& local,
Supplier s) {
Tin * tin = static_cast<Tin *>(args[0].addr);
CcString * path = static_cast<CcString *>(args[1].addr);
result = qp->ResultStorage(s);
CcBool * ret = (CcBool*) result.addr;
if (tin && tin->isDefined()) {
std::ofstream stlfile;
stlfile.open(path->GetValue().c_str(), std::ios::binary | std::ios::trunc);
if (!stlfile.is_open())
throw std::runtime_error(
"Could not open|create stl file.(Tin::tin2stl)");
if (tin->estimateMaxSizeInMemory() > OPERATE_IN_MEMORY_THRESHOLD)
tin->setMemoryStateGradual();
else
tin->setMemoryState(INMEMORY);
tin->saveSTLFile(stlfile);
stlfile.close();
ret->Set(true, true);
} else {
ret->Set(true, false);
}
return 1;
}
#endif
bool Tin::checkDelaunay() {
deque<TinPart*>::const_iterator it;
LOGP
it = tinParts.begin();
while (it != tinParts.end()) {
if (!(*it)->checkDelaunay())
return false;
it++;
}
LOGP
return true;
}
bool Tin::checkNeighborRelations() {
deque<TinPart*>::const_iterator it;
LOGP
it = tinParts.begin();
while (it != tinParts.end()) {
if (!(*it)->checkNeighborRelations())
return false;
it++;
}
LOGP
return true;
}
TinPart* Tin::getNewPart() {
TinPart * newPart;
noParts++;
newPart = TinPart::getInstanceNew(this, config);
tinParts.push_back(newPart);
LOGP
LOG(newPart)
return newPart;
}
#ifndef UNIT_TEST
TinPart* Tin::getPartFromDisc(SmiRecord & valueRecord, bool bulkload) {
TinPart * newPart;
LOGP
LOG(valueRecord.GetPos())
newPart = TinPart::getInstanceFromDisc(this, valueRecord, bulkload,
config);
tinParts.push_back(newPart);
return newPart;
}
TinPart* Tin::getPartFromDisc(uint32_t idx) {
TinPart * newPart;
SmiRecord contentRec;
if (!file.IsOpen())
throw std::runtime_error("No file. For random access "
"there has to be a file from db.(Tin::getPartFromDisc)");
if (!file.SelectRecord(contentId, contentRec, SmiFile::ReadOnly))
throw std::runtime_error("Could not open record.(Tin::getPartFromDisc)");
newPart = TinPart::getInstanceFromDiscRandomAccess(this, contentRec, idx,
config);
LOG(*newPart)
LOGP
return newPart;
}
#endif
TinPart* Tin::getNextPartIntersecting(Rectangle& bbox) {
static unsigned int i = 0;
//TODO make more efficient
while (i < tinParts.size()) {
if (tinParts[i]->bbox().hasIntersection(bbox))
return tinParts[i++];
i++;
}
if (i == tinParts.size())
i = 0;
return 0;
}
TIN_SIZE Tin::getSizeOnDisc() const {
TIN_SIZE size = 0;
LOGP
deque<TinPart*>::const_iterator it;
#ifndef UNIT_TEST
size += sizeof(SmiFileId);
size += sizeof(contentId);
size += sizeof(SmiFileId); //tree
#endif
size += sizeof(config.maxSizePart);
size += sizeof(config.abstractType);
size += sizeof(noParts);
size += features.getSizeOnDisc();
it = tinParts.begin();
while (it != tinParts.end()) {
size += (*it)->getSizeOnDisc();
++it;
}
LOGP
return size;
}
TIN_SIZE Tin::getPartHeadOrigin() const {
TIN_SIZE size = 0;
LOGP
size += sizeof(config.maxSizePart);
size += sizeof(config.abstractType);
size += sizeof(noParts);
size += features.getSizeOnDisc();
#ifndef UNIT_TEST
size += sizeof(SmiFileId); //for rtree file
#endif
LOGP
return size;
}
#ifndef UNIT_TEST
void TinAttribute::Serialize2Flob() {
LOGP
TIN_SIZE sz = getSizeOnDisc();
size_t offset = 0;
char * storage = new char[sz];
//uint8_t def = (IsDefined() ? 1 : 0);
//WriteVar<uint8_t>(def, storage, offset);
//LOG(def)
if (IsDefined()) {
//noVertices = pVertexContainer->getNoVertices();
//WriteVar<TIN_SIZE>(noTriangles, storage, offset);
//WriteVar<TIN_SIZE>(noVertices, storage, offset);
//features.serialize(storage, offset);
pVertexContainer->serialize(storage, offset);
LOG("Number of triangles:")
LOG(noTriangles)
LOGP
for (int i = 0; i < noTriangles; i++) {
LOG(i)
arTriangles[i].putSecondoRepresentation(pVertexContainer, storage,
offset);
}
binData.resize(sz);
if (!binData.write(storage, (SmiSize) sz, 0)) {
delete[] storage;
throw std::runtime_error(
"Data could not be written.(TinAttribute::Serialize2Flob)");
}
LOGP}
delete[] storage;
LOGP}
void TinAttribute::RebuildFromFlob() {
LOGP
TIN_SIZE sz = (TIN_SIZE) binData.getSize();
char * state = new char[sz];
size_t offset = 0;
LOGP
LOG(sz)
if (!binData.read(state, sz, 0)) {
delete[] state;
SetDefined(false);
throw std::runtime_error(
"Data could not be read.(TinAttribute::RebuildFromFlob)");
}
//ReadVar<uint8_t>(def, state, offset);
//LOG(def)
//SetDefined((def == 1 ? true : false));
if (IsDefined()) {
//ReadVar<TIN_SIZE>(noTriangles, state, offset);
//ReadVar<TIN_SIZE>(noVertices, state, offset);
//
//features.rebuild(state, offset);
LOG(recId)
LOG(noTriangles)
LOG(noVertices)
freeContentMemory();
initContentMemory(noVertices, noTriangles);
pVertexContainer->rebuild(state, offset);
LOGP
if (noTriangles) {
LOG(noTriangles)
LOGP
for (int i = 0; i < noTriangles; i++) {
LOG(i)
new (&arTriangles[i]) Triangle(pVertexContainer, state,
offset, this);
}
LOGP }
}
delete[] state;
LOGP}
Triangle* TinAttribute::getNeighbor(const Edge& commonEdge,
Triangle* caller) {
LOGP
return this->findEdgeInPart(commonEdge, caller);
}
bool Tin::open(SmiRecord& valueRecord, bool bypass, SmiFileId ifileid,
SmiRecordId irec) {
LOGP
SmiRecord contentRec;
SmiFileId fileid;
if (config.memoryState != INMEMORY)
throw std::runtime_error(
"Opening only in state INMEMORY ! Transistion not possible.(Tin::open)");
//Record structure root record and file:
//-fileid|contentId
//then in file pointed to by fileid and record contentId:
//config.maxSizePart|config.abstractType|noParts|treefile|features|
//-all header data of parts (see open method of TinPart)-
config.memoryState = RANDOMACCESS;
if (bypass) {
fileid = ifileid;
contentId = irec;
} else {
valueRecord.Read(fileid);
valueRecord.Read(contentId);
}
if (!file.Open(fileid))
throw std::runtime_error(E_TIN_OPEN1);
if (!file.SelectRecord(contentId, contentRec, SmiFile::ReadOnly))
throw std::runtime_error(E_TIN_OPEN);
contentRec.SetPos(0);
contentRec.Read(config.maxSizePart);
contentRec.Read(config.abstractType);
LOG("AbstractType read:")
LOG(config.abstractType)
tinTypeCurrent = config.abstractType;
contentRec.Read(noParts);
LOG("Parts read:")
LOG(noParts)
contentRec.Read(fileid);
LOG("rtree fileid:")
LOG(fileid)
if (!rtree)
rtree = new R_Tree<2, uint32_t>(fileid, file.IsTemp());
else {
delete rtree;
rtree = new R_Tree<2, uint32_t>(fileid, file.IsTemp());
}
features.open(contentRec);
LOGP
return true;
}
bool Tin::openParts(bool bulkload) {
LOGP
SmiRecord contentRec;
SmiSize sz = 0;
SmiSize offset = 0;
if (!file.IsOpen())
throw std::runtime_error(
"Cannot open parts without file.(Tin::openParts)");
if (!file.SelectRecord(contentId, contentRec, SmiFile::ReadOnly))
throw std::runtime_error(
"ContentRec could not be opened.(Tin::openParts)");
LOG(contentId)
sz = noParts * TinPart::getSizeOnDisc_head();
char * buffer = new char[sz];
contentRec.Read(buffer, sz, getPartHeadOrigin());
tinParts.resize(noParts);
for (int i = 0; i < noParts; i++) {
tinParts[i] = TinPart::getInstanceFromBuffer(this, buffer,
offset, bulkload, config);
}
delete[] buffer;
LOGP
return true;
}
bool Tin::save(SmiRecord& valueRecord, bool bypass) {
LOGP
SmiRecord contentRec;
if (config.memoryState == INMEMORY
|| config.memoryState == GRADUALTEMPORARYFILE)
throw std::runtime_error("Tried to save a tin in state stay"
" in memory or state temporary file.(Tin::save)");
//Record structure root record and file:
//-fileid|contentId
//then in file pointed to by fileid and record contentId:
//|config.maxSizePart|config.abstractType|noParts|features|
//-all header data of parts (see open method of TinPart)-
SmiFileId fileid = file.GetFileId();
if (!bypass) {
valueRecord.Write(fileid);
valueRecord.Write(contentId);
}
//save header information of Tin
if (!file.SelectRecord(contentId, contentRec, SmiFile::Update))
throw std::runtime_error("Error selecting record.(Tin::save)");
//////////////////////////////////////////////
SmiSize sz = 0;
SmiSize offset = 0;
sz = tinParts.size() * TinPart::getSizeOnDisc_head()
+ Tin::getPartHeadOrigin();
char * buffer = new char[sz];
WriteVar<TIN_SIZE>(config.maxSizePart, buffer, offset);
WriteVar<AbstractType>(config.abstractType, buffer, offset);
LOG("AbstractType written:")
LOG(config.abstractType)
LOG("Parts written:")
LOG(noParts)
WriteVar<TIN_SIZE>(noParts, buffer, offset);
if (!rtree)
rtree = new R_Tree<2, uint32_t>(
WinUnix::getPageSize() - 2 * 2 * int(sizeof(double)), file.IsTemp());
fileid = rtree->FileId();
LOG("rtree fileid:")
LOG(fileid)
WriteVar<SmiFileId>(fileid, buffer, offset);
features.serialize(buffer, offset);
LOGP
deque<TinPart*>::iterator it;
it = tinParts.begin();
while (it != tinParts.end()) {
(*it)->serialize(buffer, offset);
++it;
}
if (sz != contentRec.Write(buffer, sz, 0))
throw std::runtime_error(E_TINTYPE_SAVE1);
delete[] buffer;
//////////////////////////////////////////////
LOGP
return true;
}
SmiRecordFile* Tin::getFile() {
SmiRecord contentRec;
LOGP
if (!file.IsOpen()) {
if (config.memoryState == INMEMORY)
throw std::runtime_error(
"This tin is configured stay in memory. No file.(Tin::getFile)");
file.Create();
file.AppendRecord(contentId, contentRec);
contentRec.Finish();
}
return &file;
}
#endif
/*
The method findNeighbor tries to find the neighbor of the triangle caller
at the edge commonEdge. This is necessary at the boundary of a TinPart,
since boundary neighbors are not persisted due to small pointers.
*/
Triangle* Tin::findNeighbor(const Edge& commonEdge, Triangle* caller) {
LOGP
deque<TinPart *>::iterator it = tinParts.begin();
Triangle * result;
while (it != tinParts.end()) {
result = (*it)->findEdgeInPart(commonEdge, caller);
if (result)
return result;
it++;
}
LOGP
return 0;
}
#ifndef UNIT_TEST
std::string Tin::BasicType() {
return "tin";
}
std::string TinAttribute::BasicType() {
return "tinattribute";
}
ListExpr Tin::Property() {
ListExpr listreplist = nl->TextAtom();
ListExpr examplelist = nl->TextAtom();
ListExpr remarks = nl->TextAtom();
nl->AppendText(listreplist,
"( (maximumpartsize) ( ((triangle1_x1 triangle1_y1 triangle1_z1)"
"(triangle1_x2 triangle1_y2 triangle1_z2)(triangle1_x3"
" triangle1_y3 triangle1_z3))* )* )");
nl->AppendText(examplelist,
"( (800) ( ((-1.0 0.0 1.0)(0.0 1.0 1.0)(1.0 0.0 3.0)) ) "
" ( ((9.0 0.0 1.0)(10.0 1.0 1.0)(11.0 0.0 3.0)) ) )");
nl->AppendText(remarks,
"The TIN is partitioned in TinParts on disc. Operators "
"are acting partwise. The maximum part size configures the"
" size of these parts in bytes. Due to overhead, parts should"
" have at least page size. Tins can be created from a raster"
" or from a tuple stream. To visualize a tin use operator "
"tin2stlfile and a tool like meshlab. ");
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("-> SIMPLE"),
nl->StringAtom(Tin::BasicType()), listreplist, examplelist, remarks)));
}
ListExpr TinAttribute::Property() {
ListExpr listreplist = nl->TextAtom();
ListExpr examplelist = nl->TextAtom();
ListExpr remarks = nl->TextAtom();
nl->AppendText(listreplist,
"( (maximumpartsize) ((triangle1_x1 triangle1_y1 triangle1_z1)"
"(triangle1_x2 triangle1_y2 triangle1_z2)(triangle1_x3 triangle1_y3 "
"triangle1_z3))* )");
nl->AppendText(examplelist,
"( (800) ((-1.0 0.0 1.0)(0.0 1.0 1.0)(1.0 0.0 3.0)) "
" ((9.0 0.0 1.0)(10.0 1.0 1.0)(11.0 0.0 3.0)) )");
nl->AppendText(remarks,
"The tinattribute is actually a tin, but with the "
"ability to be used as an attribute. A tinattribute"
"consistes just of one TinPart. Tins can be converted"
"to tinattributes with operator tin2tinattribute.");
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(TinAttribute::BasicType()), listreplist, examplelist,
remarks)));
}
Word Tin::Clone(const ListExpr typeInfo, const Word& w) {
LOGP
Word result;
Tin * p = static_cast<Tin*>(w.addr);
Tin * clone = 0;
try {
if (p) {
clone = p->clone();
if (clone) {
clone->setDefined();
} else
clone = new Tin(TinConfiguration::DEFAULT, false);
} else {
clone = new Tin(TinConfiguration::DEFAULT, false);
}
} catch (std::exception& e) {
if (!clone)
clone = new Tin(TinConfiguration::DEFAULT, false);
result.addr = clone;
return result;
}
result.addr = clone;
return result;
}
Word TinAttribute::Clone(const ListExpr typeInfo, const Word& w) {
LOGP
Word result;
TinAttribute * p = static_cast<TinAttribute*>(w.addr);
if (p)
result = SetWord(p->Clone());
else
result = SetWord(new TinAttribute(false));
return result;
}
int Tin::sizeOfObj() {
return sizeof(Tin);
}
int TinAttribute::sizeOfObj() {
LOGP
return sizeof(TinAttribute);
}
bool Tin::Open(SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& value) {
LOGP
int fileState;
Tin * tt = 0;
try {
tt = new Tin(TinConfiguration::DEFAULT, false);
value.addr = tt;
valueRecord.SetPos(offset);
valueRecord.Read(fileState);
if (fileState == FILE_DAMAGED)
throw std::runtime_error(E_TIN_OPEN2);
//start with RANDOMACCESS and let operator decide
tt->open(valueRecord);
offset = valueRecord.GetPos();
} catch (std::exception &e) {
OUT_EXCEPT(e);
LOGP
return false;
}
tt->setDefined();
LOGP
return true;
}
bool Tin::Save(SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& value) {
LOGP
Tin * tt = static_cast<Tin*>(value.addr);
LOG(tt)
int fileState;
try {
valueRecord.SetPos(offset);
if (!tt || !tt->isDefined()) {
fileState = FILE_DAMAGED;
valueRecord.Write(fileState);
if (tt) {
tt->deleteFile();
if (tt->rtree)
tt->rtree->DeleteFile();
}
throw std::runtime_error(E_TIN_SAVE);
} else {
fileState = FILE_OK;
valueRecord.Write(fileState);
}
tt->setMemoryState(GRADUALFILE);
tt->save(valueRecord);
offset = valueRecord.GetPos();
} catch (std::exception & e) {
OUT_EXCEPT(e);
LOGP
return false;
}
LOGP
return true;
}
bool TinAttribute::Save(SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& value) {
LOGP
TinAttribute *bf = static_cast<TinAttribute*>(value.addr);
bf->Serialize2Flob();
// This Save function is implemented in the Attribute class
// and uses the same method of the Tuple manager to save objects
Attribute::Save(valueRecord, offset, typeInfo, bf);
return true;
}
bool TinAttribute::Open(SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& value) {
LOGP
// This Open function is implemented in the Attribute class
// and uses the same method of the Tuple manager to open objects
TinAttribute * at = static_cast<TinAttribute*>(Attribute::Open(
valueRecord, offset, typeInfo));
value = SetWord(at);
return true;
LOGP}
Word Tin::Create(const ListExpr typeInfo) {
LOGP
return (SetWord(new Tin(TinConfiguration::DEFAULT, false)));
}
Word TinAttribute::Create(const ListExpr typeInfo) {
LOGP
TinAttribute * attr = new TinAttribute(false);
Word ret = (SetWord(attr));
LOGP
LOG(ret.addr)
return ret;
}
void Tin::deleteFile() {
LOGP
if (file.IsOpen()) //a new Tin has no file yet
{
LOGP
file.Close();
file.Drop();
}
LOGP}
void Tin::Delete(const ListExpr typeInfo, Word& w) {
LOGP
deque<TinPart*>::iterator it;
Tin * ptt = (Tin*) ((((w.addr))));
if (ptt) {
if (ptt->rtree)
ptt->rtree->DeleteFile();
ptt->deleteFile();
delete ptt;
w.addr = 0;
}
LOGP}
void TinAttribute::Delete(const ListExpr typeInfo, Word& w) {
LOGP
TinAttribute * ptt = (TinAttribute*) ((((w.addr))));
ptt->binData.destroy();
delete ptt;
w.addr = 0;
LOGP}
ListExpr Tin::Out(ListExpr typeInfo, Word value) {
LOGP
Tin* t = static_cast<Tin*>(value.addr);
LOG(t)
ListExpr ret, last= nl->TheEmptyList();
deque<TinPart*>::iterator it;
LOGP
try {
if (!t || !t->isDefined())
throw std::runtime_error(E_TIN_OUT);
LOGP
LOG_EXP(t->features.print())
LOG(t->tinParts.size())
LOG(&(t->tinParts))
if (t->estimateMaxSizeInMemory() > OPERATE_IN_MEMORY_THRESHOLD)
t->setMemoryStateGradual();
else
t->setMemoryState(INMEMORY);
it = t->tinParts.begin();
if (it != t->tinParts.end()) {
last = (*it)->outPart();
(*it)->unloadContentData();
ret = nl->OneElemList(
nl->OneElemList(nl->IntAtom(t->config.maxSizePart)));
last = nl->Append(ret, last);
++it;
} else
ret = nl->Empty();
LOGP
while (it != t->tinParts.end()) {
LOG(nl->ToString(last))
last = nl->Append(last, (*it)->outPart());
(*it)->unloadContentData();
++it;
}
} catch (std::exception & e) {
OUT_EXCEPT(e);
LOGP
return nl->Empty();
}
return ret;
}
ListExpr TinAttribute::Out(ListExpr typeInfo, Word value) {
LOGP
TinAttribute* tinattr = static_cast<TinAttribute*>(value.addr);
tinattr->syncFlob(false);
ListExpr ret, last;
LOGP
try {
if (!tinattr || !tinattr->IsDefined())
throw std::runtime_error(E_TIN_OUT);
LOGP
LOG_EXP(tinattr->features.print())
last = tinattr->outPart();
ret = nl->TwoElemList(nl->IntAtom(tinattr->config.maxSizePart), last);
LOGP} catch (std::exception & e) {
OUT_EXCEPT(e);
LOGP
return nl->Empty();
}
return ret;
}
/*
Parses the configuration of a TIN from a nested list.
For now just the maximum size of a TinPart is parsed.
*/
void Tin::parseInTinConfig(const ListExpr confExp,
TinConfiguration& conf) {
string intype;
int partSize;
if (nl->IsEmpty(confExp)) //easy default config
{
conf.maxSizePart = TIN_PART_STANDARD_SIZE;
return;
} else {
if (nl->ListLength(confExp) != 1)
throw std::invalid_argument(E_PARSEINTINCONFIG1);
if (!nl->IsAtom(nl->First(confExp)))
throw std::invalid_argument(E_PARSEINTINCONFIG2);
if (!(nl->AtomType(nl->First(confExp)) == IntType))
throw std::invalid_argument(E_PARSEINTINCONFIG3);
partSize = nl->IntValue(nl->First(confExp));
conf.maxSizePart = partSize;
}
}
Word Tin::In(const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct) {
LOGP
Word obj = SetWord(Address(0));
Vertex arVertices[3];
ListExpr parts, currentPart, currentTriangle;
int noPartsl = 0;
int noTrianglesl = 0;
TinConfiguration conf;
Tin * intin = 0;
Triangle * t = 0;
correct = true;
try {
conf = TinConfiguration::DEFAULT;
intin = new Tin(conf, false);
obj.addr = intin;
Tin::parseInTinConfig(nl->First(instance), conf);
intin->config = conf;
parts = nl->Rest(instance);
noPartsl = nl->ListLength(parts);
if (intin->estimateMaxSizeInMemory(
noPartsl) > OPERATE_IN_MEMORY_THRESHOLD)
intin->setMemoryStateGradual();
else
intin->setMemoryState(INMEMORY);
LOG("noParts")
LOG(noPartsl)
while (noPartsl) {
LOGP
currentPart = nl->First(parts);
parts = nl->Rest(parts);
LOG(nl->ToString(currentPart))
//this makes a separate part for the triangles to come
intin->initSimpleLayout();
if (nl->IsEmpty(currentPart))
throw std::invalid_argument(E_TINTYPE_IN2);
noTrianglesl = nl->ListLength(currentPart);
LOG("noTriangles")
LOG(noTrianglesl)
while (noTrianglesl) {
currentTriangle = nl->First(currentPart);
currentPart = nl->Rest(currentPart);
LOGP
LOG(nl->ToString(currentTriangle))
if (nl->ListLength(currentTriangle) != 3)
throw std::runtime_error(
"There is a triangle not containing 3 vertices. (Tin::In)");
for (int i = 0; i < 3; i++) {
Vertex::parseVertex(nl->First(currentTriangle), &arVertices[i]);
currentTriangle = nl->Rest(currentTriangle);
}
intin->addTriangle(arVertices[0], arVertices[1], arVertices[2], &t);
LOGP
noTrianglesl--;
}
noPartsl--;
}
if (intin)
intin->finishLayout(false);
} catch (std::exception& e) {
OUT_EXCEPT(e);
correct = false;
LOGP
return obj;
}
intin->setDefined();
LOG(intin)
LOG(intin->config.memoryState)
LOGP
return obj;
}
Word TinAttribute::In(const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct) {
LOGP
Word obj = SetWord(Address(0));
Vertex arVertices[3];
ListExpr part, currentTriangle;
int noTrianglesl = 0;
TinConfiguration conf;
TinAttribute * intin = 0;
Triangle * t = 0;
correct = true;
try {
intin = new TinAttribute(false);
obj.addr = intin;
Tin::parseInTinConfig(nl->First(instance), conf);
intin->config.maxSizePart = conf.maxSizePart;
intin->initContentMemory();
part = nl->Rest(instance);
LOG(nl->ToString(part))
noTrianglesl = nl->ListLength(part);
LOG("noTriangles")
LOG(noTrianglesl)
while (noTrianglesl) {
currentTriangle = nl->First(part);
part = nl->Rest(part);
LOGP
LOG(nl->ToString(currentTriangle))
if (nl->ListLength(currentTriangle) != 3)
throw std::runtime_error(
"There is a triangle not containing 3 vertices. (Tin::In)");
for (int i = 0; i < 3; i++) {
Vertex::parseVertex(nl->First(currentTriangle), &arVertices[i]);
currentTriangle = nl->Rest(currentTriangle);
}
intin->addTriangle(arVertices[0], arVertices[1], arVertices[2], &t);
LOGP
noTrianglesl--;
}
} catch (std::exception& e) {
OUT_EXCEPT(e);
correct = false;
LOGP
return obj;
}
intin->SetDefined(true);
intin->syncFlob(true);
LOG_EXP(intin->features.print());
LOGP
return obj;
}
void Tin::Close(const ListExpr typeInfo, Word& w) {
delete (Tin*) ((((w.addr))));
w.addr = 0;
LOGP}
void TinAttribute::Close(const ListExpr typeInfo, Word& w) {
delete (TinAttribute*) ((((w.addr))));
w.addr = 0;
LOGP}
ListExpr Tin::atlocation_tm(ListExpr args) {
LOGP
return mappings::SimpleMaps<2, 4>(map_atlocation, args);
}
int Tin::atlocation_sf(ListExpr args) {
return mappings::SimpleSelect<2, 4>(map_atlocation, args);
}
int Tin::atlocation_vm(Word* args, Word& result, int message, Word& local,
Supplier s) {
CcReal* x = static_cast<CcReal*>(args[1].addr);
CcReal* y = static_cast<CcReal*>(args[2].addr);
Tin* tt = static_cast<Tin*>(args[0].addr);
LOGP
result = qp->ResultStorage(s);
CcReal* r = static_cast<CcReal*>(result.addr);
try {
if (!tt || !tt->isDefined())
throw std::runtime_error("Null pointer or undefined as input."
" Operation not possible. (Tin::atlocation_vm)");
double result_d = tt->atlocation(Point_p(x->GetValue(), y->GetValue()));
if (result_d == ERROR_VALUE)
r->SetDefined(false);
else
r->Set(true, result_d);
} catch (std::exception & e) {
OUT_EXCEPT(e);
r->SetDefined(false);
return -1;
}
LOGP
return 0;
}
ListExpr Tin::tinmin_tm(ListExpr args) {
return mappings::SimpleMaps<2, 2>(map_min, args);
}
int Tin::tinmin_sf(ListExpr args) {
return mappings::SimpleSelect<2, 2>(map_min, args);
}
int Tin::tinmin_vm(Word* args, Word& result, int message, Word& local,
Supplier s) {
Tin* tt = static_cast<Tin*>(args[0].addr);
LOGP
result = qp->ResultStorage(s);
CcReal* r = static_cast<CcReal*>(result.addr);
if (tt && tt->isDefined())
r->Set(true, tt->features.m_minValue);
else
r->SetDefined(false);
LOGP
return 0;
}
ListExpr Tin::tinmax_tm(ListExpr args) {
return mappings::SimpleMaps<2, 2>(map_min, args);
}
int Tin::tinmax_sf(ListExpr args) {
return mappings::SimpleSelect<2, 2>(map_min, args);
}
int Tin::tinmax_vm(Word* args, Word& result, int message, Word& local,
Supplier s) {
Tin* tt = static_cast<Tin*>(args[0].addr);
LOGP
result = qp->ResultStorage(s);
CcReal* r = static_cast<CcReal*>(result.addr);
if (tt && tt->isDefined())
r->Set(true, tt->features.m_maxValue);
else
r->SetDefined(false);
LOGP
return 0;
}
int TinAttribute::tinmax_vm(Word* args, Word& result, int message,
Word& local, Supplier s) {
TinAttribute* atin = static_cast<TinAttribute*>(args[0].addr);
LOGP
LOG(atin->features.m_minValue);LOG(atin->features.m_maxValue);
result = qp->ResultStorage(s);
CcReal* r = static_cast<CcReal*>(result.addr);
if (!atin || !atin->IsDefined()) {
r->SetDefined(false);
return -1;
}
//no sync necessary since just header data used
r->Set(true, atin->features.m_maxValue);
LOGP
return 0;
}
int TinAttribute::tinmin_vm(Word* args, Word& result, int message,
Word& local, Supplier s) {
TinAttribute* atin = static_cast<TinAttribute*>(args[0].addr);
LOGP
result = qp->ResultStorage(s);
CcReal* r = static_cast<CcReal*>(result.addr);
if (!atin || !atin->IsDefined()) {
r->SetDefined(false);
return -1;
}
//no sync necessary since just header data used
r->Set(true, atin->features.m_minValue);
LOGP
return 0;
}
int TinAttribute::atlocation_vm(Word* args, Word& result, int message,
Word& local, Supplier s) {
TinAttribute * tt = static_cast<TinAttribute *>(args[0].addr);
LOGP
CcReal* x = static_cast<CcReal*>(args[1].addr);
CcReal* y = static_cast<CcReal*>(args[2].addr);
result = qp->ResultStorage(s);
CcReal* r = static_cast<CcReal*>(result.addr);
try {
if (!tt || !tt->IsDefined())
throw std::runtime_error(
"Null. Operation not possible. (TinAttribute::atlocation_vm)");
tt->syncFlob(false);
double result_d = tt->atlocation(Point_p(x->GetValue(), y->GetValue()));
if (result_d == ERROR_VALUE)
r->SetDefined(false);
else
r->Set(true, result_d);
} catch (std::exception & e) {
OUT_EXCEPT(e);
r->SetDefined(false);
return -1;
}
LOGP
return 0;
}
ListExpr Tin::unaryOp_tm(ListExpr args) {
//tin x (real -> real) -> tin
//two arguments
if (nl->ListLength(args) != 2)
return NList::typeError("Expected two arguments.(Tin::unaryOp_tm)");
//check both types
if (!nl->IsAtom(nl->First(args))
|| !(nl->SymbolValue(nl->First(args)) == Tin::BasicType())
|| !listutils::isMap<1>(nl->Second(args)))
return NList::typeError("Expected type tin as first argument and a "
"mapping function as second argument.(Tin::unaryOp_tm)");
//check mapping functions parameter types
if (!(nl->SymbolValue(nl->Second(nl->Second(args))) == CcReal::BasicType()))
return NList::typeError(
"Expected function having one argument of type real.(Tin::unaryOp_tm)");
if (!(nl->SymbolValue(nl->Third(nl->Second(args))) == CcReal::BasicType()))
return NList::typeError(
"Expected function returning type real.(Tin::unaryOp_tm)");
LOGP
return NList(Tin::BasicType()).listExpr();
}
int Tin::unaryOp_vm(Word* args, Word& result, int message, Word& local,
Supplier s) {
void* function = args[1].addr;
Tin* tt = static_cast<Tin*>(args[0].addr);
LOGP
result = qp->ResultStorage(s);
Tin* nt = (Tin*) result.addr;
try {
if (!tt || !tt->isDefined())
throw std::runtime_error("Null pointer or undefined as input. "
"Operation not possible. (Tin::unaryOp_vm)");
LOGP
tt->unaryOp(function, nt);
LOGP} catch (std::exception & e) {
OUT_EXCEPT(e);
return -1;
}
nt->setDefined();
LOGP
return 0;
}
ListExpr Tin::raster2tin_tm(ListExpr args) {
//sreal/sint -> tin
if (nl->ListLength(args) != 2)
return NList::typeError("Expected two arguments.(Tin::raster2tin_tm)");
string raster = nl->ToString(nl->First(args));
if (!((raster == raster2::sreal::BasicType())
|| (raster == raster2::sint::BasicType())))
return NList::typeError(
"Expected first argument of type sreal.(Tin::raster2tin_tm)");
if (!nl->IsAtom(nl->Second(args)) || !nl->IntAtom(nl->Second(args)))
return NList::typeError("Expected second argument of type sint"
" (size of TinParts in bytes).(Tin::raster2tin_tm)");
return NList(Tin::BasicType()).listExpr();
}
int Tin::raster2tin_sf(ListExpr args) {
string raster = nl->ToString(nl->First(args));
if ((raster == raster2::sreal::BasicType()))
return 1;
else
return 0;
}
ListExpr Tin::createTin_tm(ListExpr args) {
ListExpr first = nl->First(args);
ListExpr attrList;
if (nl->ListLength(args) != 2 || !listutils::isTupleStream(first)
|| !nl->IsAtom(nl->Second(args)) || !nl->IntAtom(nl->Second(args))) {
return NList::typeError(E_CREATETIN_TM);
}
attrList = nl->Second(nl->Second(first));
if (nl->ListLength(attrList) != 2
|| !nl->IsAtom(nl->Second(nl->First(attrList)))
|| nl->SymbolValue(nl->Second(nl->First(attrList)))
!= ::Point::BasicType()
|| !nl->IsAtom(nl->Second(nl->Second(attrList)))
|| (nl->SymbolValue(nl->Second(nl->Second(attrList)))
!= ::CcReal::BasicType()
&& nl->SymbolValue(nl->Second(nl->Second(attrList)))
!= ::CcInt::BasicType())) {
return NList::typeError(E_CREATETIN_TM2);
}
return nl->SymbolAtom(Tin::BasicType());
}
int Tin::createTin_sf(ListExpr args) {
if (nl->SymbolValue(
nl->Second(nl->Second(nl->Second(nl->Second(nl->First(args))))))
== CcReal::BasicType())
return 0;
else
return 1;
}
ListExpr Tin::tin2tuplestream_tm(ListExpr args) {
if (nl->ListLength(args) != 1)
return NList::typeError(
"The operator tin2tuplestream expects exactly one argument.");
if (!nl->IsAtom(nl->First(args))
|| nl->SymbolValue((nl->First(args))) != Tin::BasicType())
return NList::typeError(
"The operator tin2tuplestream expects a tin as argument.");
NList tuplelist;
tuplelist.append(
nl->TwoElemList(nl->SymbolAtom("V1"),
nl->SymbolAtom(::Point::BasicType())));
tuplelist.append(
nl->TwoElemList(nl->SymbolAtom("H1"),
nl->SymbolAtom(CcReal::BasicType())));
tuplelist.append(
nl->TwoElemList(nl->SymbolAtom("V2"),
nl->SymbolAtom(::Point::BasicType())));
tuplelist.append(
nl->TwoElemList(nl->SymbolAtom("H2"),
nl->SymbolAtom(CcReal::BasicType())));
tuplelist.append(
nl->TwoElemList(nl->SymbolAtom("V3"),
nl->SymbolAtom(::Point::BasicType())));
tuplelist.append(
nl->TwoElemList(nl->SymbolAtom("H3"),
nl->SymbolAtom(CcReal::BasicType())));
tuplelist.append(
nl->TwoElemList(nl->SymbolAtom("Part"),
nl->SymbolAtom(CcInt::BasicType())));
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
tuplelist.listExpr()));
}
/*
pdcheck
*/
int Tin::tin2tuplestream_vm(Word* args, Word& result, int message,
Word& local, Supplier s) {
Tin* tin;
tin2tuplestreamState *state = 0;
ListExpr tupleType;
try {
switch (message) {
case OPEN:
tin = (Tin*) args[0].addr;
if (!tin || !tin->isDefined()) {
throw std::runtime_error(
"Input is null pointer or undefined.(Tin::tin2tuplestream)");
}
if (tin->estimateMaxSizeInMemory() > OPERATE_IN_MEMORY_THRESHOLD)
tin->setMemoryStateGradual();
else
tin->setMemoryState(INMEMORY);
tupleType = GetTupleResultType(s);
state = new tin2tuplestreamState;
state->itTriangles = new Tin::triangle_iterator(tin);
state->tupleType = new TupleType(nl->Second(tupleType));
local = SetWord(state);
LOGP
return 0;
case REQUEST:
LOGP
if (local.addr)
state = (tin2tuplestreamState*) local.addr;
else
return CANCEL;
if ((*(*state->itTriangles))) {
Tuple * t = new Tuple(state->tupleType);
const Vertex * v1 = (*(*state->itTriangles))->getVertex(1);
const Vertex * v2 = (*(*state->itTriangles))->getVertex(2);
const Vertex * v3 = (*(*state->itTriangles))->getVertex(3);
::Point * p = new ::Point(true, v1->getX(), v1->getY());
CcReal * h = new CcReal(true, v1->getZ());
t->PutAttribute(0, p);
t->PutAttribute(1, h);
p = new ::Point(true, v2->getX(), v2->getY());
h = new CcReal(true, v2->getZ());
t->PutAttribute(2, p);
t->PutAttribute(3, h);
p = new ::Point(true, v3->getX(), v3->getY());
h = new CcReal(true, v3->getZ());
t->PutAttribute(4, p);
t->PutAttribute(5, h);
CcInt *part = new CcInt(state->itTriangles->getCurrentPart());
t->PutAttribute(6, part);
(*state->itTriangles)++;
result = SetWord(t);
return YIELD;
} else
return CANCEL;
case CLOSE:
if (local.addr) {
state = (tin2tuplestreamState*) local.addr;
LOGP
delete state;
local.addr = 0;
}
return 0;
}
} catch (std::exception & e) {
OUT_EXCEPT(e);
result.addr = 0;
return CANCEL;
}
return 0;
}
ListExpr Tin::tin2tinattribute_tm(ListExpr args) {
if (nl->ListLength(args) != 1)
return NList::typeError(
"The operator tin2tinattribute expects exactly one argument.");
if (!nl->IsAtom(nl->First(args))
|| nl->SymbolValue((nl->First(args))) != Tin::BasicType())
return NList::typeError(
"The operator tin2tinattribute expects a tin as argument.");
NList tuplelist;
tuplelist.append(
nl->TwoElemList(nl->SymbolAtom("TinPart"),
nl->SymbolAtom(TinAttribute::BasicType())));
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
tuplelist.listExpr()));
}
TinAttribute::TinAttribute(TinPart & part) :
Attribute(true),
binData(0) {
bool n;
const Vertex * v1, *v2, *v3;
LOGP
part.loadContentData();
config = part.tin->getConfiguration();
config.memoryState = INMEMORY;
noTriangles = 0;
features = part.features;
contentLoaded = true;
ismodified = true;
pVertexContainer = part.pVertexContainer->clone_empty();
arTriangles = new Triangle[part.noTriangles];
for (int i = 0; i < part.noTriangles; i++) {
v1 = pVertexContainer->insertVertex(part.arTriangles[i].getVertex(1), n);
v2 = pVertexContainer->insertVertex(part.arTriangles[i].getVertex(2), n);
v3 = pVertexContainer->insertVertex(part.arTriangles[i].getVertex(3), n);
constructTriangle(v1, v2, v3);
noTriangles++;
LOGP}
noVertices = pVertexContainer->getNoVertices();
contentRefs = 0;
noTrianglesMax = part.noTrianglesMax;
SetDefined(true);
#ifndef UNIT_TEST
isRecInitialized = false;
#endif
syncFlob(true);
LOGP}
int Tin::tin2tinattribute_vm(Word* args, Word& result, int message,
Word& local, Supplier s) {
Tin* tin;
tin2tinattributestreamState * state;
ListExpr tupleType;
try {
switch (message) {
case OPEN:
tin = (Tin*) args[0].addr;
if (!tin || !tin->isDefined()) {
throw std::runtime_error(
"Input is null pointer or undefined.(Tin::tin2tinattribute)");
}
if (tin->estimateMaxSizeInMemory() > OPERATE_IN_MEMORY_THRESHOLD)
tin->setMemoryStateGradual();
else
tin->setMemoryState(INMEMORY);
tupleType = GetTupleResultType(s);
state = new tin2tinattributestreamState;
state->tupleType = new TupleType(nl->Second(tupleType));
state->itParts = tin->tinParts.begin();
state->itEnd = tin->tinParts.end();
local = SetWord(state);
LOGP
return 0;
case REQUEST:
LOGP
if (local.addr)
state = (tin2tinattributestreamState*) local.addr;
else
return CANCEL;
if (state->itParts != state->itEnd) {
Tuple * t = new Tuple(state->tupleType);
TinAttribute * attr = new TinAttribute(*(*(state->itParts)));
t->PutAttribute(0, attr);
++(state->itParts);
result = SetWord(t);
return YIELD;
} else
return CANCEL;
case CLOSE:
if (local.addr) {
state = (tin2tinattributestreamState*) local.addr;
LOGP
delete state;
local.addr = 0;
}
return 0;
}
} catch (std::exception & e) {
OUT_EXCEPT(e);
result.addr = 0;
return CANCEL;
}
return 0;
}
/*
pdcheck
*/
ListExpr TinAttribute::tinattribute2tin_tm(ListExpr args) {
ListExpr attrList;
ListExpr str = nl->First(args);
if (nl->ListLength(args) != 1 || !listutils::isTupleStream(str)) {
return NList::typeError("The operator tinattribute2tin "
"expects exactly one argument of type"
" tuple stream. (TinAttribute::tinattribute2tin_tm)");
}
attrList = nl->Second(nl->Second(str));
if (nl->ListLength(attrList) != 1
|| !nl->IsAtom(nl->Second(nl->First(attrList)))
|| nl->SymbolValue(nl->Second(nl->First(attrList)))
!= TinAttribute::BasicType()) {
return NList::typeError("The tuples of the input"
" tuple stream have to consist of just one "
"attribute of type tinattribute."
"(TinAttribute::tinattribute2tin_tm)");
}
return nl->SymbolAtom(Tin::BasicType());
}
int TinAttribute::tinattribute2tin_sf(ListExpr args) {
return 0;
}
TinPart* TinAttribute::clone(Tin*tt) {
if (!IsDefined())
return 0;
LOGP
LOG_EXP(features.print())
syncFlob(false);
return TinPart::clone(tt);
}
int TinAttribute::tinattribute2tin_vm(Word* args, Word& result,
int message, Word& local, Supplier s) {
LOGP
Stream<Tuple> stream(args[0]);
result = qp->ResultStorage(s);
Tin * nt = (Tin*) result.addr;
Tuple * currentTuple;
TinAttribute * currentTinattr;
TinPart * copyPart;
bool first = true;
TinConfiguration targetConf;
try {
if (args[0].addr == 0)
throw std::runtime_error("Null pointer as input."
" Operation not possible. (TinAttribute::tinattribute2tin_vm)");
LOGP
stream.open();
while ((currentTuple = stream.request()) != 0) {
currentTinattr = (TinAttribute *) currentTuple->GetAttribute(0);
if (first) {
targetConf = currentTinattr->config;
nt->resetConfiguration(targetConf);
first = false;
} else if (!(targetConf == currentTinattr->config)) {
throw std::runtime_error("The stream of tinattributes contains"
" an attribute with a different configuration."
" (e.g. an attribute with a different part size)"
" The conversion is not possible currently."
" (TinAttribute::tinattribute2tin_vm)");
}
copyPart = currentTinattr->clone(nt);
if (copyPart)
nt->addPart(copyPart);
currentTuple->DeleteIfAllowed();
}
LOGP} catch (std::exception & e) {
OUT_EXCEPT(e);
nt->setDefined(false);
stream.close();
return -1;
}
nt->setDefined(true);
stream.close();
LOGP
return 0;
}
#endif
ColumnKey::ColumnKey(VERTEX_COORDINATE ixfrom, VERTEX_COORDINATE ixto,
uint32_t inoPart) {
xFrom = ixfrom;
xTo = ixto;
noPart = inoPart;
}
ColumnKey::ColumnKey(VERTEX_COORDINATE ix, uint32_t inoPart) {
xFrom = ix;
xTo = ix;
noPart = inoPart;
}
ColumnKey::~ColumnKey() {
}
bool ColumnKey::operator<(const ColumnKey & ckey) const {
if (ckey.xFrom == ckey.xTo) {
if (ckey.xFrom < xFrom)
return false;
if (ckey.xFrom > xTo)
return true;
return false;
}
if (xFrom == xTo) {
if (xFrom < ckey.xFrom)
return true;
if (xFrom > ckey.xTo)
return false;
return false;
}
if (xFrom < ckey.xFrom)
return true;
else
return false;
}
/* namespace tin*/
}