Files
secondo/Algebras/Spatial3D/TriangleContainer.cpp

491 lines
12 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
01590 Fachpraktikum "Erweiterbare Datenbanksysteme"
WS 2014 / 2015
<our names here>
//paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}]
//paragraph [10] Footnote: [{\footnote{] [}}]
//[TOC] [\tableofcontents]
[1] Implementation of a Spatial3D algebra
[TOC]
1 Includes and Defines
*/
#include "Spatial3D.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "MMRTree.h"
#include "geometric_algorithm.h"
#include "Spatial3DTransformations.h"
extern NestedList* nl;
extern QueryProcessor* qp;
extern AlgebraManager* am;
using namespace std;
TriangleContainer::TriangleContainer()
: TransformObject() { }
TriangleContainer::TriangleContainer(bool def)
: TransformObject(def),
pointFlob(0), triangleFlob(0), bulkloadData(0) { }
TriangleContainer::TriangleContainer(const TriangleContainer& src)
: TransformObject(src.IsDefined()),
pointFlob(src.pointFlob.Size()),
triangleFlob(src.pointFlob.Size()),
bulkloadData(0)
{
pointFlob.copyFrom(src.pointFlob);
triangleFlob.copyFrom(src.triangleFlob);
boundingBox = src.boundingBox;
}
TriangleContainer::TriangleContainer(int n)
: TransformObject(true), pointFlob(n), triangleFlob(n), bulkloadData(0) { }
TriangleContainer::~TriangleContainer()
{
if (bulkloadData != NULL) {
delete bulkloadData;
}
}
void TriangleContainer::clear()
{
pointFlob.clean();
triangleFlob.clean();
boundingBox.SetDefined(false);
}
void TriangleContainer::startBulkLoad()
{
// startBulkLoad() must not be called again while bulkload is active
assert(bulkloadData == NULL);
bulkloadData = new BulkloadData();
}
bool TriangleContainer::endBulkLoad(BulkLoadOptions options)
{
assert(bulkloadData != 0);
if (bulkloadData->getStatus() == ERROR
|| (bulkloadData->hasCorrections() && ((options & REPAIR) == 0))
|| !checkBulkloadData(options))
{
triangleFlob.clean();
pointFlob.clean();
boundingBox.SetDefined(false);
SetDefined(false);
}
else
{
SetDefined(true);
vector<Triangle> triangles;
bulkloadData->getContainer().exportObject(1, triangles);
// Clear the old data structures before we construct our own tree
bulkloadData->getContainer().removeObject(1);
mmrtree::RtreeT<3, size_t> points(4,8);
for (vector<Triangle>::iterator it = triangles.begin();
it != triangles.end(); ++it)
{
TrianglePointIndices pointIndices;
pointIndices.pointIndexA = addPoint(it->getA());
pointIndices.pointIndexB = addPoint(it->getB());
pointIndices.pointIndexC = addPoint(it->getC());
triangleFlob.Append(pointIndices);
}
}
delete bulkloadData;
bulkloadData = 0;
return true;
}
bool TriangleContainer::checkBulkloadData(BulkLoadOptions options) const
{
return true;
}
int TriangleContainer::addPoint(const Point3d& point)
{
/* First, compare coordinates with existing points. If there is a
* matching point, just return its index. Otherwise, we create a new
* point.
*/
SimplePoint3d simplePoint(point);
mmrtree::RtreeT<3, size_t>::iterator* it;
Rectangle<3> bbox = point.BoundingBox();
bbox.Extend(0.0001);
it = bulkloadData->getPoints().find(bbox);
size_t const * index;
while( (index = it->next()) != 0)
{
SimplePoint3d p;
pointFlob.Get(*index, p);
if (AlmostEqual(simplePoint.getX(), p.getX()) &&
AlmostEqual(simplePoint.getY(), p.getY()) &&
AlmostEqual(simplePoint.getZ(), p.getZ()))
{
delete it;
return *index;
}
}
delete it;
int res = pointFlob.Size();
pointFlob.Append(simplePoint);
bulkloadData->getPoints().insert(bbox, res);
return res;
}
void TriangleContainer::add(const Triangle& triangle)
{
/* add may only be called while bulkload is active */
assert(bulkloadData != NULL);
if(bulkloadData->getStatus() == ERROR)
{
return;
}
if (! spatial3d_geometric::isValidTriangle(triangle))
{
bulkloadData->correction();
return;
}
MultiObjectTriangleContainer& container = bulkloadData->getContainer();
bool res = container.addTriangle(triangle, 1, bulkloadData->hasCorrections());
if (!res && !bulkloadData->hasCorrections())
{
bulkloadData->correction();
res = container.addTriangle(triangle, 1, true);
}
if (!res)
{
bulkloadData->error();
}
else
{
Rectangle<3> boundingBoxA = ((Point3d)(triangle.getA())).BoundingBox();
if (boundingBox.IsDefined())
{
boundingBox.Extend(boundingBoxA);
}
else
{
boundingBox = boundingBoxA;
}
boundingBox.Extend(((Point3d)(triangle.getB())).BoundingBox());
boundingBox.Extend(((Point3d)(triangle.getC())).BoundingBox());
}
}
int TriangleContainer::size() const
{
return triangleFlob.Size();
}
Triangle TriangleContainer::get(int index) const
{
assert(index >= 0 && index < size());
TrianglePointIndices indices;
triangleFlob.Get(index, indices);
SimplePoint3d spA, spB, spC;
pointFlob.Get(indices.pointIndexA, spA);
pointFlob.Get(indices.pointIndexB, spB);
pointFlob.Get(indices.pointIndexC, spC);
Point3d pA(spA.getX(), spA.getY(), spA.getZ());
Point3d pB(spB.getX(), spB.getY(), spB.getZ());
Point3d pC(spC.getX(), spC.getY(), spC.getZ());
return Triangle(pA, pB, pC);
}
Rectangle<3> TriangleContainer::getBoundingBox() const
{
//We also want to have empty volumes...
//assert(size() > 0);
return boundingBox;
}
int TriangleContainer::NumOfFLOBs() const
{
return 2;
}
Flob* TriangleContainer::GetFLOB(int i)
{
switch (i)
{
case 0:
return &pointFlob;
case 1:
return &triangleFlob;
default:
assert(false);
return NULL;
}
}
bool TriangleContainer::Adjacent(const Attribute *arg) const
{
return false;
}
size_t TriangleContainer::HashValue() const
{
return 0; // TODO: sinnvoller Wert (Jens Breit)
}
NList TriangleContainer::getPointList(int pointIndex)
{
SimplePoint3d p;
pointFlob.Get(pointIndex, p);
return NList(p.getX(), p.getY(), p.getZ());
}
NList TriangleContainer::getTriangleList(int triangleIndex)
{
TrianglePointIndices pointIndices;
triangleFlob.Get(triangleIndex, pointIndices);
return NList(getPointList(pointIndices.pointIndexA),
getPointList(pointIndices.pointIndexB),
getPointList(pointIndices.pointIndexC));
}
ListExpr TriangleContainer::ToListExpr(ListExpr typeInfo)
{
if (IsDefined())
{
NList result(nl);
for (int ti = 0; ti < triangleFlob.Size(); ++ti)
{
result.append(getTriangleList(ti));
}
return result.listExpr();
}
else
{
return listutils::getUndefined();
}
}
bool TriangleContainer::checkPoint(NList value)
{
if (value.length() != 3)
{
return false;
}
return listutils::isNumeric(value.first ().listExpr())
&& listutils::isNumeric(value.second().listExpr())
&& listutils::isNumeric(value.third ().listExpr());
}
bool TriangleContainer::checkTriangle(NList value)
{
if (value.length() != 3)
{
return false;
}
return checkPoint(value.first())
&& checkPoint(value.second())
&& checkPoint(value.third());
}
bool TriangleContainer::checkTriangleList(NList value)
{
/* SJ: We want an empty list, too
if (length < 1)
{
return false;
}
*/
while (!value.isEmpty())
{
if (!checkTriangle(value.first()))
{
return false;
}
value.rest();
}
return true;
}
Point3d TriangleContainer::readPoint(NList value)
{
double x, y, z;
x = listutils::getNumValue(value.first ().listExpr());
y = listutils::getNumValue(value.second().listExpr());
z = listutils::getNumValue(value.third ().listExpr());
Point3d newPoint(x, y, z);
return newPoint;
}
void TriangleContainer::readTriangle(NList value)
{
add(Triangle(readPoint(value.first()),
readPoint(value.second()),
readPoint(value.third())));
// TODO: check (Jens Breit)
}
void TriangleContainer::readTriangleList(NList value)
{
while (!value.isEmpty())
{
readTriangle(value.first());
value.rest();
}
}
bool TriangleContainer::ReadFrom(ListExpr value, ListExpr typeInfo)
{
if (listutils::isSymbolUndefined(value))
{
SetDefined(false);
return true;
}
if (checkTriangleList(NList(value)))
{
SetDefined(true);
//SJ: init bbox here (just in case we have an empty list
boundingBox= Rectangle<3>(false);
pointFlob.resize(nl->ListLength(value) * 3);
triangleFlob.resize(nl->ListLength(value));
startBulkLoad();
readTriangleList(NList(value));
endBulkLoad(NO_REPAIR);
return true;
}
else
{
return false;
}
}
int TriangleContainer::CompareTriangleContainer(
const TriangleContainer *other) const
{
if (!this->IsDefined())
{
return other->IsDefined() ? -1 : 0;
}
if (!other->IsDefined())
{
return 1;
}
if (this->triangleFlob.Size() < other->triangleFlob.Size())
{
return -1;
}
if (this->triangleFlob.Size() > other->triangleFlob.Size())
{
return 1;
}
if (this->pointFlob.Size() < other->pointFlob.Size())
{
return -1;
}
if (this->pointFlob.Size() > other->pointFlob.Size())
{
return 1;
}
// TODO (Jens Breit)
return 0;
}
void TriangleContainer::copyTrianglesFrom(const TriangleContainer& src)
{
pointFlob.copyFrom(src.pointFlob);
triangleFlob.copyFrom(src.triangleFlob);
boundingBox = src.boundingBox;
}
const Rectangle<3> TriangleContainer::BoundingBox(const Geoid* geoid) const
{
return boundingBox;
}
double TriangleContainer::Distance(const Rectangle<3>& rect,
const Geoid* geoid = 0) const
{
return rect.Distance(BoundingBox()); // TODO: sinnvollerer Wert (Jens Breit)
}
bool TriangleContainer::Intersects(const Rectangle<3>& rect,
const Geoid* geoid = 0) const
{
return rect.Intersects(BoundingBox()); // TODO: sinnvollerer Wert (Jens Breit)
}
void TriangleContainer::rotate(const Point3d* center,const Vector3d* axis,
double angle, TriangleContainer& res)
{
spatial3DTransformations::rotateTriangleContainer(
this,center,axis,angle,res);
}
void TriangleContainer::mirror(const Plane3d* plane, TriangleContainer& res)
{
spatial3DTransformations::mirrorTriangleContainer(this,plane,res);
}
void TriangleContainer::translate(const Vector3d* translation,
TriangleContainer& res)
{
spatial3DTransformations::translateTriangleContainer(this,translation,res);
}
void TriangleContainer::scaleDir(const Point3d* center,
const Vector3d* direction, TriangleContainer& res)
{
spatial3DTransformations::scaleDirTriangleContainer(
this,center,direction,res);
}
void TriangleContainer::scale(const Point3d* center,
double factor, TriangleContainer& res)
{
spatial3DTransformations::scaleTriangleContainer(this,center,factor,res);
}