Files
secondo/Algebras/Spatial3D/Spatial3DConvert.cpp

1602 lines
44 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
//paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}]
//paragraph [10] Footnote: [{\footnote{] [}}]
//[TOC] [\tableofcontents]
//[NP] [\newpage]
//[ue] [\"u]
//[e] [\'e]
----
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
Jens Breit, Joachim Dechow, Daniel Fuchs, Simon Jacobi, G[ue]nther Milosits,
Daijun Nagamine, Hans-Joachim Klauke.
Betreuer: Dr. Thomas Behr, Fabio Vald[e]s
[1] Implementation of a Spatial3D algebra:
region2volume, region2surface, mregion2volume
[TOC]
[NP]
1 Includes and Defines
*/
#include <cmath>
#include <list>
#include <algorithm> // std::min
#include <time.h>
#include "Spatial3D.h"
#include "Spatial3DConvert.h"
#include "Spatial3DSetOps.h"
#include "Triangulate.h"
#include "Algebras/Spatial/SpatialAlgebra.h"
#include "Algebras/MovingRegion/MovingRegionAlgebra.h"
extern NestedList* nl;
extern QueryProcessor* qp;
using namespace std;
using namespace temporalalgebra;
namespace spatial3DConvert {
/*
1 Some auxiliary functions for the creations:
1.1 ~det~
Calculate the determinant of a matrix with the three points as columns.
*/
double det(Point& a, Point& b, Point& c){
long double r = ((long double)a.GetX() * (long double)b.GetY()
+ (long double)b.GetX() * (long double)c.GetY()
+ (long double)c.GetX() * (long double)a.GetY())
- ((long double)c.GetX() * (long double)b.GetY()
+ (long double)b.GetX() * (long double)a.GetY()
+ (long double)a.GetX() * (long double)c.GetY());
return(double)r;
}
/*
1.2 ~pointIsBetween~
Verify wether a point lies on the line between two points.
d is the value of the determinant.
*/
bool pointIsBetween(double d, Point& a, Point& b, Point& c){
double epsilon = 0.0000000001;
if(abs(d) < epsilon &&
((a.GetX() < max(b.GetX(),c.GetX()) &&
(a.GetX() > min(b.GetX(),c.GetX()))) || (a.GetY() < max(b.GetY(),c.GetY())
&& (a.GetY() > min(b.GetY(),c.GetY()))))){
return true;
}
return false;
}
/*
1.3 ~intersect~
Calculates wether the two segents a-b and c-d intersect each other:
*/
bool intersect(Point& a, Point& b, Point& c, Point& d){
//1. They are the same:
if((AlmostEqual(a,c) && AlmostEqual(b,d)) ||
(AlmostEqual(a,d) && AlmostEqual(b,c))){
return true;
}
//2. One segment is left of the other
double minX1 = min(a.GetX(),b.GetX());
double maxX1 = max(a.GetX(),b.GetX());
double minX2 = min(c.GetX(),d.GetX());
double maxX2 = max(c.GetX(),d.GetX());
if((maxX1 < minX2) || (minX1 > maxX2)){
return false;
}
//3. One segment is above the other
double minY1 = min(a.GetY(),b.GetY());
double maxY1 = max(a.GetY(),b.GetY());
double minY2 = min(c.GetY(),d.GetY());
double maxY2 = max(c.GetY(),d.GetY());
if((maxY1 < minY2) || (minY1 > maxY2)){
return false;
}
//If the points are on different sides of the segment,
//the dets have different signs.
//If all dets are 0 then the segments are in one line,
//and because of 2. and 3. they overlap.
double s1 = det(a,c,d);
double s2 = det(b,c,d);
double s3 = det(c,a,b);
double s4 = det(d,a,b);
double epsilon = 0.0000000001;
if(
(abs(s1) < epsilon && abs(s2) < epsilon &&
abs(s3) < epsilon && abs(s4) < epsilon ) ||
(s1 < -epsilon && s2 > epsilon && s3 < -epsilon && s4 > epsilon) ||
(s1 < -epsilon && s2 > epsilon && s3 > epsilon && s4 < -epsilon) ||
(s1 > epsilon && s2 < -epsilon && s3 < -epsilon && s4 > epsilon) ||
(s1 > epsilon && s2 < -epsilon && s3 > epsilon && s4 < -epsilon)){
return true;
}
if(
pointIsBetween(s1,a,c,d) ||
pointIsBetween(s2,b,c,d) ||
pointIsBetween(s3,c,a,b) ||
pointIsBetween(s4,d,a,b)){
return true;
}
return false;
}
/*
1.4 ~segmentIntersectPolygon~
Calculates wether the segent intersect the polygon:
*/
bool segmentIntersectPolygon(Point& p1,Point& p2, list<Point>& list){
std::list<Point>::iterator it = list.begin();
Point l1 = (*it);
Point l2 = l1;
++it;
while (it != list.end()){
l2 = l1;
l1 = (*it);
if(intersect(p1, p2, l1, l2)){
return true;
}
++it;
}
return false;
}
/*
1.5 ~pointIsLeftOf~
Point x is left of the segment a-b
*/
bool pointIsLeftOf(Point& x, Point& a, Point& b){
double minY = min(a.GetY(),b.GetY());
double maxY = max(a.GetY(),b.GetY());
if(x.GetY() < minY || x.GetY() > maxY){
return false;
}
double maxX = max(a.GetX(),b.GetX());
if(x.GetX() > maxX){
return false;
}
long double q = ((long double)x.GetY() - (long double)a.GetY()) /
((long double)b.GetY() - (long double)a.GetY());
long double ab = (long double)a.GetX() +
q * ((long double)b.GetX() - (long double)a.GetX());
//endpoints only count once
if(x.GetX() < (double)ab && q != 1.0){
return true;
}
return false;
}
/*
1.6 ~pointIsInsideOfThePolygon~
When a point is inside a polygon,
then there is a uneven number of segments left of the point.
*/
bool pointIsInsideOfThePolygon(Point& p, list<Point>& list){
int count = 0;
std::list<Point>::iterator it = list.begin();
Point l1 = (*it);
Point l2 = l1;
++it;
while (it != list.end()){
l2 = l1;
l1 = (*it);
if(pointIsLeftOf(p,l1,l2)){
count++;
}
++it;
}
if(count % 2 == 0){
return false;
}
return true;
}
/*
1.7 ~pointsAreDiagonal~
The segment between two points of the polygon is a diagonal if it
does not intercect other parts of the polygon and is inside of the polygon.
*/
bool pointsAreDiagonal(Point& p1,Point& p2, list<Point>& list){
if(AlmostEqual(p1,p2)){
return false;
}
if(segmentIntersectPolygon(p1,p2,list)){
return false;
}
Point p(true, 0.5 * (p1.GetX() + p2.GetX()), 0.5 * (p1.GetY() + p2.GetY()));
if(pointIsInsideOfThePolygon(p,list)){
return true;
}
return false;
}
/*
1.9 ~cutPolygonOnPoints~
The polygon will be spitted into two polygons
*/
void cutPolygonOnPoints(std::list<Point>::iterator it1,
std::list<Point>::iterator it2,
std::list<Point>& list, std::list<Point>& newList){
Point first = *it1;
Point last = *it2;
++it1;
std::list<Point>::iterator it;
// while((*it1) != (*it2)){
while((it1 != it2)){
newList.push_back(*it1);
it = it1;
++it1;
list.erase(it);
}
newList.push_front(first);
newList.push_back(last);
newList.push_back(first);
}
/*
1.10 ~listIsClockwise~
The points in the list run clockwise around the polygon.
*/
bool listIsClockwise(list<Point>& list){
//Gauss's area formula
std::list<Point>::iterator it1 = list.begin();
std::list<Point>::iterator it2 = it1;
if(it1 != list.end()){
++it1;
}
double A = 0;
while(it1 != list.end()){
Point p1 = *it1;
Point p2 = *it2;
A += p1.GetX() * p2.GetY() - p1.GetY() * p2.GetX();
it2 = it1;
++it1;
}
return A > 0;
}
/*
1.11 ~addTriangle~
Add a triangle to the TriangleContainer
*/
void addTriangle(TriangleContainer& res, Point p1,
Point p2,Point p3, bool bottom, double heigth){
//bottom means that the triangle is clockwise oriented.
//Gauss's area formula
double A = (p1.GetX() * p2.GetY()) +
(p2.GetX() * p3.GetY()) +
(p3.GetX() * p1.GetY()) -
(p2.GetX() * p1.GetY()) -
(p3.GetX() * p2.GetY()) -
(p1.GetX() * p3.GetY());
if((bottom && A < 0) || (!bottom && A > 0)){
res.add(Triangle(Point3d(p1.GetX(),p1.GetY(),heigth),
Point3d(p2.GetX(),p2.GetY(),heigth),
Point3d(p3.GetX(),p3.GetY(),heigth)));
}else{
res.add(Triangle(Point3d(p1.GetX(),p1.GetY(),heigth),
Point3d(p3.GetX(),p3.GetY(),heigth),
Point3d(p2.GetX(),p2.GetY(),heigth)));
}
}
/*
1.12 ~triangulation~
Every polygon with more than tree points, has a diagonal with two corner
pointsthat lies totaly inside the polygon.
So it is possible to split the polygon on that points,
~bottom~ defines whether all Triangles are clockwise orientated (true),
~heigth~ defines the z Coordinate of the points of the triangles.
*/
void triangulation(TriangleContainer& res, list<Point>& list,
double heigth1, bool clockwise1,
double heigth2, bool clockwise2){
if(list.size() < 4){
res.SetDefined(false);
return;
}
//put the list on a stack
stack< std::list<Point> > stack;
stack.push(list);
//do while there is a list on the stack
while(!stack.empty()){
//take the first list of the stack
std::list<Point> actualList = stack.top();
stack.pop();
if(actualList.size() < 4){
cout << "The list should always have more than 3 elements!" << endl;
}
//the list is a triangle
if(actualList.size() == 4){
std::vector<Point> v;
for (std::list<Point>::iterator it = actualList.begin();
it != actualList.end(); ++it){
v.push_back(*it);
}
addTriangle(res, v[0], v[1], v[2], clockwise1, heigth1);
if(heigth2 > 0.0){
addTriangle(res, v[0], v[1], v[2], clockwise2, heigth2);
}
}else{
//the list will be splited at a diagonal
bool found = false;
for (std::list<Point>::iterator it1 = actualList.begin();
(it1 != actualList.end() && !found); ++it1){
Point p1 = *it1;
std::list<Point>::iterator it2 = it1;
//try every possible segment
//there must be at least one diagonal
while((it2 != actualList.end()) && !found){
Point p2 = *it2;
//Find the diagonal
if(pointsAreDiagonal(p1, p2, actualList)){
found = true;
std::list<Point> newList;
//cut the polygon
cutPolygonOnPoints(it1, it2, actualList, newList);
if(actualList.size() < 4 ||newList.size() < 4){
cout << "List should always have more than 3 elements!" << endl;
return;
}
//Put the two new lists on the stack
stack.push(newList);
stack.push(actualList);
it2 == actualList.end();
break;
}
if(it2 != actualList.end()){
++it2;
}
}
}
if(found == false){
cout << "The triangulation does not work!" << endl;
std::list<Point>::iterator ita = actualList.begin();
while(ita != actualList.end()){
cout << "Punkt X:" << (*ita).GetX() << endl;
cout << "Punkt Y:" << (*ita).GetY() << endl << endl;
++ita;
}
}
}
}
}
/*
1.12 ~triangulation~
Alternative triangulation using the class HPolygon
from algebra TransportationMode
*/
void triangulation2(TriangleContainer& res, vector<list<Point> >& lists,
double heigth1, bool clockwise1,
double heigth2, bool clockwise2){
int ncontours = lists.size();
int cntr[ncontours];
vector<double> vertices_x;
vector<double> vertices_y;
for(int i = 0; i < ncontours;i++){
list<Point> list = lists[i];
cntr[i] = list.size();
std::list<Point>::iterator it = list.begin();
while(it != list.end()){
Point p = *it;
vertices_x.push_back(p.GetX());
vertices_y.push_back(p.GetY());
++it;
}
}
Copied_from_Algebra_TransportationMode::HPolygon poly;
poly.Init2(ncontours, cntr, vertices_x,vertices_y);
cout<< "start Triangulation." << endl;
poly.Triangulate();
cout<< "end Triangulation." << endl;
for (unsigned int i=0; i< poly.mtabCell.size(); ++i){
if(heigth2 == 0.0){
addTriangle(res,
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(0)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(0)].Y()),
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(1)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(1)].Y()),
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(2)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(2)].Y()),
clockwise1, heigth1);
}else{
addTriangle(res,
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(0)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(0)].Y()),
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(1)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(1)].Y()),
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(2)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(2)].Y()),
clockwise1, heigth1);
addTriangle(res,
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(0)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(0)].Y()),
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(1)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(1)].Y()),
Point(true,poly.mtabPnt[poly.mtabCell[i].Index(2)].X(),
poly.mtabPnt[poly.mtabCell[i].Index(2)].Y()),
clockwise2, heigth2);
}
}
cout<< "leave Triangulation." << endl;
}
/*
1.13 ~addSides~
Adds the triang on the sides of the volume.
*/
void addSides(TriangleContainer& res, list<Point>& list,
double heigth, bool listIsClockwise){
std::list<Point>::iterator it1 = list.begin();
std::list<Point>::iterator it2 = it1;
if(it1 != list.end()){
++it1;
}
while(it1 != list.end()){
Point p1 = *it1;
Point p2 = *it2;
cout<< "P1 x: " << p1.GetX() << endl;
cout<< "P1 y: " << p1.GetY() << endl;
cout<< "P2 x: " << p2.GetX() << endl;
cout<< "P2 y: " << p2.GetY() << endl;
if(listIsClockwise){
res.add(Triangle(Point3d(p2.GetX(),p2.GetY(),heigth),
Point3d(p1.GetX(),p1.GetY(),heigth),
Point3d(p1.GetX(),p1.GetY(),0)));
res.add(Triangle(Point3d(p2.GetX(),p2.GetY(),heigth),
Point3d(p1.GetX(),p1.GetY(),0),
Point3d(p2.GetX(),p2.GetY(),0)));
}else{
res.add(Triangle(Point3d(p2.GetX(),p2.GetY(),heigth),
Point3d(p1.GetX(),p1.GetY(),0),
Point3d(p1.GetX(),p1.GetY(),heigth)));
res.add(Triangle(Point3d(p2.GetX(),p2.GetY(),heigth),
Point3d(p2.GetX(),p2.GetY(),0),
Point3d(p1.GetX(),p1.GetY(),0)));
}
it2 = it1;
++it1;
}
}
/*
1.14 ~triangulationToSurface~
The result of the triangulation is added to a surface.
*/
void triangulationToSurface(TriangleContainer& res, list<Point>& list){
res.startBulkLoad();
vector<std::list<Point> > lists;
lists.push_back(list);
triangulation2(res, lists, 0.0,false,0.0, false);
// triangulation(res, list, 0.0,false,0.0, false);
res.endBulkLoad(NO_REPAIR);
}
/*
1.14 ~triangulationToSurface~
The result of the triangulation is added to a surface.
With the use of HPolygon.
*/
void triangulationToSurface(TriangleContainer& res,
vector<list<Point> >& lists){
triangulation2(res, lists, 0.0,false,0.0, false);
}
/*
1.15 ~triangulationToVolume~
The result of the triangulation is added to a volume.
*/
void triangulationToVolume(TriangleContainer& res, list<Point>& list,
double heigth){
res.startBulkLoad();
triangulation(res, list, 0.0,true, heigth, false);
bool clockwise = listIsClockwise(list);
addSides(res, list, heigth, clockwise);
res.endBulkLoad(NO_REPAIR);
}
/*
1.15 ~triangulationToVolume~
The result of the triangulation is added to a volume.
*/
void triangulationToVolume(TriangleContainer& res, vector<list<Point> >& lists,
double heigth){
triangulation2(res, lists, 0.0,true, heigth, false);
cout<< "Start add sides." << endl;
if(lists.size() > 0){
bool clockwise = listIsClockwise(lists[0]);
cout<< "aussen" << endl;
addSides(res, lists[0], heigth, clockwise);
for(unsigned int i = 1;i < lists.size(); i++){
cout<< i << endl;
clockwise = listIsClockwise(lists[i]);
addSides(res, lists[i], heigth, !clockwise);
}
}
cout<< "End add sides." << endl;
}
/*
1.16 ~region2list~
Builds a list of points that represent a polygon
of the outer circle of the region.
The first and the last point of the list have to be the same.
For the region we assume that the edgeno are ordered in the cycle
the first havesegment has the number of the face and
the number of the other cycle
we assume hat every region has only one face and that
the first halfsegment is part of the border of the face.
*/
void region2list(Region* r,list<Point>& list){
int size = r->Size();
if(size < 3){
cout << "The region should have more than 2 elements!" << endl;
return;
}
HalfSegment hs;
HalfSegment hs2;
Point rp;
Point lp;
Point rp2;
Point lp2;
Point firstpoint;
Point nextpoint;
//find first
r->Get(0,hs);
int faceno = hs.attr.faceno;
int cycleno = hs.attr.cycleno;
int edgeno = hs.attr.edgeno;
edgeno++;
int oldedgeno;
lp = hs.GetLeftPoint();
rp = hs.GetRightPoint();
//find second
//because we don't know whether the left or the right point is the beginning
for (int i=1; i < size;i++){
r->Get(i,hs2);
if((hs2.attr.faceno == faceno) &&
(hs2.attr.cycleno == cycleno) &&
(hs2.attr.edgeno == edgeno)){
lp2 = hs2.GetLeftPoint();
rp2 = hs2.GetRightPoint();
if(AlmostEqual(lp2,lp)){
list.push_back(rp);
list.push_back(lp);
list.push_back(rp2);
nextpoint = rp2;
firstpoint = rp;
} else if (AlmostEqual(lp2,rp)){
list.push_back(lp);
list.push_back(rp);
list.push_back(rp2);
nextpoint = rp2;
firstpoint = lp;
} else if (AlmostEqual(rp2,lp)){
list.push_back(rp);
list.push_back(lp);
list.push_back(lp2);
nextpoint = lp2;
firstpoint = rp;
} else if (AlmostEqual(rp2,rp)){
list.push_back(lp);
list.push_back(rp);
list.push_back(lp2);
nextpoint = lp2;
firstpoint = lp;
}
edgeno++;
break;
}
}
//find next
while(!AlmostEqual(nextpoint,firstpoint)){
oldedgeno = edgeno;
for (int i=0; i < size;i++){
r->Get(i,hs);
if((hs.attr.faceno == faceno) &&
(hs.attr.cycleno == cycleno) &&
(hs.attr.edgeno == edgeno)){
lp = hs.GetLeftPoint();
rp = hs.GetRightPoint();
if(AlmostEqual(lp,nextpoint)){
list.push_back(rp);
nextpoint = rp;
} else if (AlmostEqual(rp,nextpoint)){
list.push_back(lp);
nextpoint = lp;
} else {
break;
}
edgeno++;
break;
}
}
if(oldedgeno == edgeno){
break;
}
}
}
/*
1.17 ~getURegionEmbFaceCount~
Returns the number of faces of an object with type URegionEmb.
*/
int getURegionEmbFaceCount(MRegion* mr, URegionEmb& ur){
unsigned int count = ur.GetSegmentsNum();
int pos = ur.GetStartPos();
DbArray<MSegmentData>* segments =
(DbArray<MSegmentData>*)mr->GetFLOB(1);
int maxIndex = -1;
for (unsigned int i = 0; i < count; i++) {
MSegmentData segment;
segments->Get(pos + i, segment);
maxIndex = max(maxIndex, (int)segment.GetFaceNo());
}
return maxIndex + 1;
}
/*
1.18 ~getURegionEmbFaceCount~
Returns the number of holes in an face of an object with type URegionEmb.
*/
int getURegionEmbCycleCount(MRegion* mr, URegionEmb& ur,unsigned int faceNo){
unsigned int count = ur.GetSegmentsNum();
int pos = ur.GetStartPos();
DbArray<MSegmentData>* segments =
(DbArray<MSegmentData>*)mr->GetFLOB(1);
int maxIndex = -1;
for (unsigned int i = 0; i < count; i++) {
MSegmentData segment;
segments->Get(pos + i, segment);
if(segment.GetFaceNo() == faceNo){
maxIndex = max(maxIndex, (int)segment.GetCycleNo());
}
}
return maxIndex + 1;
}
/*
1.19 ~uregion2listInitial~ and uregion2listFinal
Builds 2 lists of points that represent a polygon
of the outer circle of the mregion at the begin and the end of the interval.
The first and the last point of the list have to be the same.
For the region we assume that the edgeno are ordered in the cycle.
We assume hat every region has only one face and that
the face has cycle number 0. Cycle with other numbers represent holes.
*/
void uregion2listInitial(
MRegion* mr,
URegionEmb& ur,
list<Point>& listInitial,
unsigned int faceNo,
unsigned int cycleNo){
unsigned int count = ur.GetSegmentsNum();
int pos = ur.GetStartPos();
DbArray<MSegmentData>* segments =
(DbArray<MSegmentData>*)mr->GetFLOB(1);
unsigned int segmentno = 0;
unsigned int startsegment = 0;
while(true){
for (unsigned int i = 0; i < count; i++) {
startsegment = segmentno;
MSegmentData segment;
segments->Get(pos + i, segment);
if(segment.GetFaceNo() == faceNo &&
segment.GetCycleNo() == cycleNo &&
segment.GetSegmentNo() == segmentno){
if(segmentno == 0){
listInitial.push_back(
Point(true,segment.GetInitialStartX(),segment.GetInitialStartY()));
}
if(!segment.GetPointInitial()){
listInitial.push_back(
Point(true,segment.GetInitialEndX(),segment.GetInitialEndY()));
}
segmentno++;
}
}
if((segmentno == count) || (startsegment == segmentno)){
return;
}
}
}
void uregion2listFinal(
MRegion* mr,
URegionEmb& ur,
list<Point>& listFinal,
unsigned int faceNo,
unsigned int cycleNo){
unsigned int count = ur.GetSegmentsNum();
int pos = ur.GetStartPos();
DbArray<MSegmentData>* segments =
(DbArray<MSegmentData>*)mr->GetFLOB(1);
unsigned int segmentno = 0;
unsigned int startsegment = 0;
while(true){
for (unsigned int i = 0; i < count; i++) {
startsegment = segmentno;
MSegmentData segment;
segments->Get(pos + i, segment);
if(segment.GetFaceNo() == faceNo &&
segment.GetCycleNo() == cycleNo &&
segment.GetSegmentNo() == segmentno){
if(segmentno == 0){
listFinal.push_back(
Point(true,segment.GetFinalStartX(),segment.GetFinalStartY()));
}
if(!segment.GetPointFinal()){
listFinal.push_back(
Point(true,segment.GetFinalEndX(),segment.GetFinalEndY()));
}
segmentno++;
}
}
if((segmentno == count) || (startsegment == segmentno)){
return;
}
}
}
/*
1.20 ~addMSides~
Adds the triangle on the sides of the volume build from a MRegion object.
*/
void addMSides(
MRegion* mr,
URegionEmb& ur,
TriangleContainer& res,
double heigthInitial,
double heigthFinal,
bool listIsClockwise,
unsigned int faceNo,
unsigned int cycleNo){
unsigned int count = ur.GetSegmentsNum();
int pos = ur.GetStartPos();
DbArray<MSegmentData>* segments =
(DbArray<MSegmentData>*)mr->GetFLOB(1);
unsigned int segmentno = 0;
unsigned int startsegment = 0;
while(true){
for (unsigned int i = 0; i < count; i++) {
startsegment = segmentno;
MSegmentData segment;
segments->Get(pos + i, segment);
if(segment.GetFaceNo() == faceNo &&
segment.GetCycleNo() == cycleNo &&
segment.GetSegmentNo() == segmentno){
//build triangle for sides
if(!segment.GetPointInitial()){
if(listIsClockwise){
res.add(Triangle(
Point3d(segment.GetFinalStartX(),
segment.GetFinalStartY(),
heigthFinal),
Point3d(segment.GetInitialEndX(),
segment.GetInitialEndY(),
heigthInitial),
Point3d(segment.GetInitialStartX(),
segment.GetInitialStartY(),
heigthInitial)));
}else{
res.add(Triangle(
Point3d(segment.GetFinalStartX(),
segment.GetFinalStartY(),
heigthFinal),
Point3d(segment.GetInitialStartX(),
segment.GetInitialStartY(),
heigthInitial),
Point3d(segment.GetInitialEndX(),
segment.GetInitialEndY(),
heigthInitial)));
}
}
if(!segment.GetPointFinal()){
if(listIsClockwise){
res.add(Triangle(
Point3d(segment.GetFinalStartX(),
segment.GetFinalStartY(),
heigthFinal),
Point3d(segment.GetFinalEndX(),
segment.GetFinalEndY(),
heigthFinal),
Point3d(segment.GetInitialEndX(),
segment.GetInitialEndY(),
heigthInitial)));
}else{
res.add(Triangle(
Point3d(segment.GetFinalStartX(),
segment.GetFinalStartY(),
heigthFinal),
Point3d(segment.GetInitialEndX(),
segment.GetInitialEndY(),
heigthInitial),
Point3d(segment.GetFinalEndX(),
segment.GetFinalEndY(),
heigthFinal)));
}
}
segmentno++;
}
}
if((segmentno == count) || (startsegment == segmentno)){
return;
}
}
}
/*
1.21 ~region2surface~
Main auxiliary function for the operator ~region2surface~.
*/
void region2surfaceOld(Region* r, Surface3d& res){
//A region could have n faces
vector<Region*> components;
r->Components(components );
//Every region in components has now only 1 face
std::vector<Region*>::iterator it = components.begin();
Surface3d* faces = new Surface3d(1);
faces->clear();
faces->startBulkLoad();
Surface3d* holes = new Surface3d(1);
holes->clear();
holes->startBulkLoad();
while (it != components.end()){
std::list<Point> list;
region2list((*it),list);
Surface3d* face = new Surface3d(1);
triangulationToSurface(*face, list);
//Every face could have n holes
Region* rholes = new Region(1);
(*it)->getHoles(*rholes);
vector<Region*> holecomponents;
rholes->Components(holecomponents);
std::vector<Region*>::iterator ith = holecomponents.begin();
while (ith != holecomponents.end()){
std::list<Point> listh;
region2list((*ith),listh);
Surface3d* hole = new Surface3d(1);
triangulationToSurface(*hole, listh);
int sizeh = hole->size();
for(int i = 0; i < sizeh; i++){
holes->add(hole->get(i));
}
delete hole;
++ith;
}
for(std::vector<Region*>::iterator ithc = holecomponents.begin();
ithc != holecomponents.end();++ithc){
delete (*ithc);
}
delete rholes;
int size = face->size();
for(int i = 0; i < size; i++){
faces->add(face->get(i));
}
delete face;
++it;
}
for(std::vector<Region*>::iterator itc = components.begin();
itc != components.end();++itc){
delete (*itc);
}
holes->endBulkLoad(NO_REPAIR);
faces->endBulkLoad(NO_REPAIR);
//ToDo: wenn Jens und Simon mit performSetOperation
// fertig sind aktivieren. Bis dahin geht es nur ohne Loecher!
bool performSetOperationWorks = false;
if(holes->size() > 0 && performSetOperationWorks){
spatial3DSetOps::performSetOperation (
spatial3DSetOps::set_minus, *faces, *holes, res);
}else{
res.clear();
res.startBulkLoad();
int size = faces->size();
for(int i = 0; i < size; i++){
res.add(faces->get(i));
}
res.endBulkLoad(NO_REPAIR);
}
delete holes;
delete faces;
}
/*
1.21 ~region2surface~
Main auxiliary function for the operator ~region2surface~.
*/
void region2surface(Region* r, Surface3d& res){
res.clear();
res.startBulkLoad();
//A region could have n faces
vector<Region*> components;
r->Components(components );
//Every region in components has now only 1 face
std::vector<Region*>::iterator it = components.begin();
Surface3d* faces = new Surface3d(1);
faces->clear();
faces->startBulkLoad();
Surface3d* holes = new Surface3d(1);
holes->clear();
holes->startBulkLoad();
int count = 1;
while (it != components.end()){
vector<std::list<Point> > lists;
std::list<Point> list;
region2list((*it),list);
lists.push_back(list);
//Every face could have n holes
Region* rholes = new Region(1);
(*it)->getHoles(*rholes);
vector<Region*> holecomponents;
rholes->Components(holecomponents);
std::vector<Region*>::iterator ith = holecomponents.begin();
while (ith != holecomponents.end()){
std::list<Point> listh;
region2list((*ith),listh);
lists.push_back(listh);
++ith;
}
triangulationToSurface(res, lists);
cout << "End Triangulation: " << count++ << endl;
for(std::vector<Region*>::iterator ithc = holecomponents.begin();
ithc != holecomponents.end();++ithc){
delete (*ithc);
}
delete rholes;
++it;
}
for(std::vector<Region*>::iterator itc = components.begin();
itc != components.end();++itc){
delete (*itc);
}
res.endBulkLoad(NO_REPAIR);
}
/*
1.22 ~region2volume~
Main auxiliary function for the operator ~region2volume~.
*/
void region2volumeOld(Region* r,double h, Volume3d& res){
//A region could have n faces
vector<Region*> components;
r->Components(components );
//Every region in components has now only 1 face
std::vector<Region*>::iterator it = components.begin();
Volume3d* faces = new Volume3d(1);
faces->clear();
faces->startBulkLoad();
Volume3d* holes = new Volume3d(1);
holes->clear();
holes->startBulkLoad();
while (it != components.end()){
std::list<Point> list;
region2list((*it),list);
Volume3d* face = new Volume3d(1);
triangulationToVolume(*face, list, h);
//Every face could have n holes
Region* rholes = new Region(1);
(*it)->getHoles(*rholes);
vector<Region*> holecomponents;
rholes->Components(holecomponents);
std::vector<Region*>::iterator ith = holecomponents.begin();
while (ith != holecomponents.end()){
std::list<Point> listh;
region2list((*ith),listh);
Volume3d* hole = new Volume3d(1);
triangulationToVolume(*hole, listh, h);
int sizeh = hole->size();
for(int i = 0; i < sizeh; i++){
holes->add(hole->get(i));
}
delete hole;
++ith;
}
for(std::vector<Region*>::iterator ithc = holecomponents.begin();
ithc != holecomponents.end();++ithc){
delete (*ithc);
}
delete rholes;
int size = face->size();
for(int i = 0; i < size; i++){
faces->add(face->get(i));
}
delete face;
++it;
}
for(std::vector<Region*>::iterator itc = components.begin();
itc != components.end();++itc){
delete (*itc);
}
holes->endBulkLoad(NO_REPAIR);
faces->endBulkLoad(NO_REPAIR);
//ToDo: wenn Jens und Simon mit performSetOperation
// fertig sind aktivieren. Bis dahin geht es nur ohne Loecher!
bool performSetOperationWorks = false;
if(holes->size() > 0 && performSetOperationWorks){
spatial3DSetOps::performSetOperation (
spatial3DSetOps::set_minus, *faces, *holes, res);
}else{
res.clear();
res.startBulkLoad();
int size = faces->size();
for(int i = 0; i < size; i++){
res.add(faces->get(i));
}
res.endBulkLoad(NO_REPAIR);
}
delete holes;
delete faces;
}
/*
1.22 ~region2volume~
Main auxiliary function for the operator ~region2volume~.
*/
void region2volume(Region* r,double h, Volume3d& res){
res.clear();
res.startBulkLoad();
//A region could have n faces
vector<Region*> components;
r->Components(components );
//Every region in components has now only 1 face
std::vector<Region*>::iterator it = components.begin();
Surface3d* faces = new Surface3d(1);
faces->clear();
faces->startBulkLoad();
Surface3d* holes = new Surface3d(1);
holes->clear();
holes->startBulkLoad();
while (it != components.end()){
std::list<Point> list;
region2list((*it),list);
vector<std::list<Point> > lists;
lists.push_back(list);
//Every face could have n holes
Region* rholes = new Region(1);
(*it)->getHoles(*rholes);
vector<Region*> holecomponents;
rholes->Components(holecomponents);
std::vector<Region*>::iterator ith = holecomponents.begin();
while (ith != holecomponents.end()){
std::list<Point> listh;
region2list((*ith),listh);
lists.push_back(listh);
++ith;
}
triangulationToVolume(res, lists, h);
for(std::vector<Region*>::iterator ithc = holecomponents.begin();
ithc != holecomponents.end();++ithc){
delete (*ithc);
}
delete rholes;
++it;
}
for(std::vector<Region*>::iterator itc = components.begin();
itc != components.end();++itc){
delete (*itc);
}
res.endBulkLoad(NO_REPAIR);
}
/*
1.23 ~mregion2volume~
Main auxiliary function for the operator ~mregion2volume~.
*/
void mregion2volumeOld(MRegion* mr,double h, Volume3d& res){
Volume3d* faces = new Volume3d(1);
faces->clear();
faces->startBulkLoad();
Volume3d* holes = new Volume3d(1);
holes->clear();
holes->startBulkLoad();
int noComponents = mr->GetNoComponents();
double startHeigth = 0.0;
for(int componentNo = 0; componentNo < noComponents; componentNo++){
URegionEmb ur;
mr->Get(componentNo,ur);
Instant duration = ur.getTimeInterval().end - ur.getTimeInterval().start;
double heigth = h * ((double)duration.GetDay() +
(double)duration.GetAllMilliSeconds() / (double)86400000);
int noFaces = getURegionEmbFaceCount(mr, ur);
for(int faceNo = 0; faceNo < noFaces; faceNo++){
//the face
list<Point> listInitial;
uregion2listInitial(mr, ur,listInitial, faceNo, 0);
bool clockwise = listIsClockwise(listInitial);
list<Point> listFinal;
uregion2listFinal(mr, ur,listFinal, faceNo, 0);
addMSides(mr, ur,*faces, startHeigth,
startHeigth + heigth, clockwise, faceNo, 0);
if(componentNo == 0){
triangulation(*faces, listInitial, startHeigth, true, 0.0, false);
}
if(componentNo == (noComponents - 1)){
triangulation(*faces, listFinal, startHeigth + heigth, false,
0.0, false);
}
//the holes
int noCycles = getURegionEmbCycleCount(mr, ur, faceNo);
for(int cycleNo = 1; cycleNo < noCycles; cycleNo++){
list<Point> listHoleInitial;
uregion2listInitial(mr, ur,listHoleInitial, faceNo, cycleNo);
bool clockwise = listIsClockwise(listHoleInitial);
list<Point> listHoleFinal;
uregion2listFinal(mr, ur,listHoleFinal, faceNo, cycleNo);
addMSides(mr, ur,*holes, startHeigth, startHeigth + heigth,
clockwise, faceNo, cycleNo);
if(componentNo == 0){
triangulation(*holes, listHoleInitial, startHeigth, true,
0.0, false);
}
if(componentNo == (noComponents - 1)){
triangulation(*holes, listHoleFinal, startHeigth + heigth, false,
0.0, false);
}
}
startHeigth += heigth;
}
}
holes->endBulkLoad(NO_REPAIR);
faces->endBulkLoad(NO_REPAIR);
//ToDo: wenn Jens und Simon mit performSetOperation
// fertig sind aktivieren. Bis dahin geht es nur ohne Loecher!
bool performSetOperationWorks = false;
if(holes->size() > 0 && performSetOperationWorks){
spatial3DSetOps::performSetOperation (
spatial3DSetOps::set_minus, *faces, *holes, res);
}else{
res.clear();
res.startBulkLoad();
int size = faces->size();
for(int i = 0; i < size; i++){
res.add(faces->get(i));
}
res.endBulkLoad(NO_REPAIR);
}
delete holes;
delete faces;
}
/*
1.23 ~mregion2volume~
Main auxiliary function for the operator ~mregion2volume~.
*/
void mregion2volume(MRegion* mr,double h, Volume3d& res){
res.clear();
res.startBulkLoad();
int noComponents = mr->GetNoComponents();
double startHeigth = 0.0;
for(int componentNo = 0; componentNo < noComponents; componentNo++){
URegionEmb ur;
mr->Get(componentNo,ur);
vector<std::list<Point> > initialLists;
vector<std::list<Point> > finalLists;
Instant duration = ur.getTimeInterval().end - ur.getTimeInterval().start;
double heigth = h * ((double)duration.GetDay() +
(double)duration.GetAllMilliSeconds() / (double)86400000);
int noFaces = getURegionEmbFaceCount(mr, ur);
for(int faceNo = 0; faceNo < noFaces; faceNo++){
//the face
list<Point> listInitial;
uregion2listInitial(mr, ur,listInitial, faceNo, 0);
bool clockwise = listIsClockwise(listInitial);
list<Point> listFinal;
uregion2listFinal(mr, ur,listFinal, faceNo, 0);
addMSides(mr, ur,res, startHeigth,
startHeigth + heigth, clockwise, faceNo, 0);
initialLists.push_back(listInitial);
finalLists.push_back(listFinal);
//the holes
int noCycles = getURegionEmbCycleCount(mr, ur, faceNo);
for(int cycleNo = 1; cycleNo < noCycles; cycleNo++){
list<Point> listHoleInitial;
uregion2listInitial(mr, ur,listHoleInitial, faceNo, cycleNo);
bool clockwise = listIsClockwise(listHoleInitial);
list<Point> listHoleFinal;
uregion2listFinal(mr, ur,listHoleFinal, faceNo, cycleNo);
addMSides(mr, ur,res, startHeigth, startHeigth + heigth,
!clockwise, faceNo, cycleNo);
initialLists.push_back(listHoleInitial);
finalLists.push_back(listHoleFinal);
}
if(componentNo == 0){
triangulation2(res, initialLists, startHeigth, true, 0.0, false);
}
if(componentNo == (noComponents - 1)){
triangulation2(res, finalLists, startHeigth + heigth, false,
0.0, false);
}
startHeigth += heigth;
}
}
res.endBulkLoad(NO_REPAIR);
}
/*
10 Operators
Definition of operators is similar to definition of type constructors. An
operator is defined by creating an instance of class ~Operator~. Again we
have to define some functions before we are able to create an ~Operator~
instance.
10.1 Type mapping functions
A type mapping function takes a nested list as argument. Its contents are
type descriptions of an operator's input parameters. A nested list describing
the output type of the operator is returned.
10.1.1 Type mapping function Spatial3DRegion2SurfaceMap.
This type mapping function is used for the ~region2surface~ operator.
*/
ListExpr Spatial3DRegion2SurfaceMap( ListExpr args )
{
if ( nl->ListLength( args ) != 1 )
{ ErrorReporter::ReportError("wrong number of arguments (1 expected)");
return nl->TypeError();
}
ListExpr arg1 = nl->First(args);
if(nl->AtomType(arg1)!=SymbolType){
ErrorReporter::ReportError("region expected");
return nl->TypeError();
}
string st = nl->SymbolValue(arg1);
if( st!=Region::BasicType()){
ErrorReporter::ReportError("region expected");
return nl->TypeError();
}
st = Surface3d::BasicType();
return nl->SymbolAtom(st);
}
/*
10.1.2 Type mapping function Spatial3DRegion2VolumeMap
This type mapping function is used for the ~region2volume~
operator.
*/
ListExpr Spatial3DRegion2VolumeMap( ListExpr args )
{
if ( nl->ListLength( args ) != 2 )
{ ErrorReporter::ReportError("wrong number of arguments (2 expected)");
return nl->TypeError();
}
ListExpr arg1 = nl->First(args);
ListExpr arg2 = nl->Second(args);
if(nl->AtomType(arg1)!=SymbolType){
ErrorReporter::ReportError("region x real expected");
return nl->TypeError();
}
string st = nl->SymbolValue(arg1);
if( st!=Region::BasicType()){
ErrorReporter::ReportError("region x real expected");
return nl->TypeError();
}
if(!nl->IsEqual(arg2,CcReal::BasicType())){
ErrorReporter::ReportError("region x real expected");
return nl->TypeError();
}
st = Volume3d::BasicType();
return nl->SymbolAtom(st);
}
/*
10.1.3 Type mapping function Spatial3DMRegion2VolumeMap
This type mapping function is used for the ~mregion2volume~
operator.
*/
ListExpr Spatial3DMRegion2VolumeMap( ListExpr args )
{
if ( nl->ListLength( args ) != 2 )
{ ErrorReporter::ReportError("wrong number of arguments (2 expected)");
return nl->TypeError();
}
ListExpr arg1 = nl->First(args);
ListExpr arg2 = nl->Second(args);
if(nl->AtomType(arg1)!=SymbolType){
ErrorReporter::ReportError("mregion x real expected");
return nl->TypeError();
}
string st = nl->SymbolValue(arg1);
if( st!=MRegion::BasicType()){
ErrorReporter::ReportError("mregion x real expected");
return nl->TypeError();
}
if(!nl->IsEqual(arg2,CcReal::BasicType())){
ErrorReporter::ReportError("mregion x real expected");
return nl->TypeError();
}
st = Volume3d::BasicType();
return nl->SymbolAtom(st);
}
/*
10.4 Value mapping functions
10.4.1 Value mapping functions of operator ~createCube~
*/
int Spatial3DRegion2Surface( Word* args, Word& result, int message,
Word& local, Supplier s ){
result = qp->ResultStorage(s);
Surface3d* res = static_cast<Surface3d*>(result.addr);
Region* r = static_cast<Region*>(args[0].addr);
if(!r->IsDefined()){
res->SetDefined(false);
return 0;
}
region2surface(r,*res);
return 0;
}
int Spatial3DRegion2Volume( Word* args, Word& result, int message,
Word& local, Supplier s ){
result = qp->ResultStorage(s);
Volume3d* res = static_cast<Volume3d*>(result.addr);
CcReal* ch = static_cast<CcReal*>(args[1].addr);
Region* r = static_cast<Region*>(args[0].addr);
if(!r->IsDefined() || !ch->IsDefined()){
res->SetDefined(false);
return 0;
}
double h = ch->GetRealval();
region2volume(r,h,*res);
return 0;
}
int Spatial3DMRegion2Volume( Word* args, Word& result, int message,
Word& local, Supplier s ){
result = qp->ResultStorage(s);
Volume3d* res = static_cast<Volume3d*>(result.addr);
CcReal* ch = static_cast<CcReal*>(args[1].addr);
MRegion* r = static_cast<MRegion*>(args[0].addr);
if(!r->IsDefined() || !ch->IsDefined()){
res->SetDefined(false);
return 0;
}
double h = ch->GetRealval();
mregion2volume(r,h,*res);
return 0;
}
/*
10.5 Definition of operators
Definition of operators is done in a way similar to definition of
type constructors: an instance of class ~Operator~ is defined.
10.5.2 Definition of specification strings
*/
const string Spatial3DSpecRegion2Surface =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>(region) -> surface3d</text--->"
"<text> region2surface(r)</text--->"
"<text> creates a surface3d from a region</text--->"
"<text> query region2surface(region)</text--->"
") )";
const string Spatial3DSpecRegion2Volume =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>(region) -> volume3d</text--->"
"<text> region2volume(r,h)</text--->"
"<text> creates a volume3d with heigth h from a region</text--->"
"<text> query region2volume(region,h)</text--->"
") )";
const string Spatial3DSpecMRegion2Volume =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>(mregion) -> volume3d</text--->"
"<text> mregion2volume(r,h)</text--->"
"<text> creates a volume3d from a mregion</text--->"
"<text> query mregion2volume(mregion,h)</text--->"
") )";
/*
10.5.3 Definition of the operators
*/
Operator* getRegion2SurfacePtr(){
return new Operator(
"region2surface",
Spatial3DSpecRegion2Surface,
Spatial3DRegion2Surface,
Operator::SimpleSelect,
Spatial3DRegion2SurfaceMap
);
}
Operator* getRegion2VolumePtr(){
return new Operator(
"region2volume",
Spatial3DSpecRegion2Volume,
Spatial3DRegion2Volume,
Operator::SimpleSelect,
Spatial3DRegion2VolumeMap
);
}
Operator* getMRegion2VolumePtr(){
return new Operator(
"mregion2volume",
Spatial3DSpecMRegion2Volume,
Spatial3DMRegion2Volume,
Operator::SimpleSelect,
Spatial3DMRegion2VolumeMap
);
}
}