/* ---- 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 #endif #include 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::iterator itParts; deque::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::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::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::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::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::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::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::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::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::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::iterator it = tinParts.begin(); std::stack 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::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::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::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& 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 p; //clear existing Layout finishLayout(); //just one column with a new part p.first = ColumnKey(-std::numeric_limits::max(), std::numeric_limits::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 > incompleteParts; std::pair p; std::map::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::max(), std::numeric_limits::max(), p.first.getNoPart()); incompleteParts.pop(); } else { p.first = ColumnKey(-std::numeric_limits::max(), std::numeric_limits::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::max(), noPart); else if (i == 0) p.first = ColumnKey(-std::numeric_limits::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::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, ¬riangles, 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::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::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::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(this)->setMemoryState(INMEMORY); } else { LOGP tt->setMemoryState(GRADUALTEMPORARYFILE); const_cast(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::const_iterator it; LOGP #ifndef UNIT_TEST if (this->estimateMaxSizeInMemory() * 2 < OPERATE_IN_MEMORY_THRESHOLD) { LOGP result->setMemoryState(INMEMORY); const_cast(this)->setMemoryState(INMEMORY); } else { LOGP result->setMemoryStateGradual(); const_cast(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(args[0].addr); CcString * path = static_cast(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::const_iterator it; LOGP it = tinParts.begin(); while (it != tinParts.end()) { if (!(*it)->checkDelaunay()) return false; it++; } LOGP return true; } bool Tin::checkNeighborRelations() { deque::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::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(def, storage, offset); //LOG(def) if (IsDefined()) { //noVertices = pVertexContainer->getNoVertices(); //WriteVar(noTriangles, storage, offset); //WriteVar(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(def, state, offset); //LOG(def) //SetDefined((def == 1 ? true : false)); if (IsDefined()) { //ReadVar(noTriangles, state, offset); //ReadVar(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(config.maxSizePart, buffer, offset); WriteVar(config.abstractType, buffer, offset); LOG("AbstractType written:") LOG(config.abstractType) LOG("Parts written:") LOG(noParts) WriteVar(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(fileid, buffer, offset); features.serialize(buffer, offset); LOGP deque::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::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(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(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(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(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(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::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(value.addr); LOG(t) ListExpr ret, last= nl->TheEmptyList(); deque::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(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(args[1].addr); CcReal* y = static_cast(args[2].addr); Tin* tt = static_cast(args[0].addr); LOGP result = qp->ResultStorage(s); CcReal* r = static_cast(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(args[0].addr); LOGP result = qp->ResultStorage(s); CcReal* r = static_cast(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(args[0].addr); LOGP result = qp->ResultStorage(s); CcReal* r = static_cast(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(args[0].addr); LOGP LOG(atin->features.m_minValue);LOG(atin->features.m_maxValue); result = qp->ResultStorage(s); CcReal* r = static_cast(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(args[0].addr); LOGP result = qp->ResultStorage(s); CcReal* r = static_cast(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(args[0].addr); LOGP CcReal* x = static_cast(args[1].addr); CcReal* y = static_cast(args[2].addr); result = qp->ResultStorage(s); CcReal* r = static_cast(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(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 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*/ }