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

2882 lines
79 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2008, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
//[ue] [\"u]
//[ae] [\"a]
//[oe] [\"o]
//[x] [$\times $]
//[->] [$\rightarrow $]
[1] Implementation of the Set Operator Classes
April - November 2008, M. H[oe]ger for bachelor thesis.
[TOC]
1 Introduction
This file essentially contains the implementations of several classes which
provide the core functionality of the three set operators
~intersection~, ~union~ and ~minus~ with the signature \\
movingregion [x] movingregion [->] movingregion \\
used in the MovingRegionAlgebra.
2 Defines and Includes
*/
#include "SetOps.h"
using namespace std;
using namespace datetime;
namespace temporalalgebra{
namespace mregionops {
set<unsigned int> flippedPFaces;
Statistic statistic;
/*
1 Class SetOperator
*/
void SetOperator::Intersection() {
Operate(INTERSECTION);
}
void SetOperator::Union() {
Operate(UNION);
}
void SetOperator::Minus() {
Operate(MINUS);
}
void SetOperator::Operate(const SetOp op) {
//flippedPFaces.clear();
if (!a->IsDefined() || !b->IsDefined()) {
res->SetDefined(false);
return;
}
// Compute the RefinementPartition of the
// two MRegions:
RefinementPartition<
MRegion,
MRegion,
URegionEmb,
URegionEmb> rp(*a, *b);
#ifdef PRINT_STATISTIC
statistic.Reset();
statistic.noUnitsIn = rp.Size();
//cout << "RefinementPartition with " << rp.Size() << " units created.";
//cout << endl;
#endif
Interval<Instant> interval;
int aPos;
int bPos;
bool aIsEmpty;
bool bIsEmpty;
MRegion* tempA;
MRegion* tempB;
URegionEmb unitA;
URegionEmb unitB;
URegionEmb unitARestrict;
URegionEmb unitBRestrict;
URegionEmb* unitARestrictCopy;
URegionEmb* unitBRestrictCopy;
const DbArray<MSegmentData>* aArray;
const DbArray<MSegmentData>* bArray;
SourceUnitPair* so;
res->Clear();
((DbArray<MSegmentData>*)res->GetFLOB(1))->clean();
res->StartBulkLoad();
for (unsigned int i = 0; i < rp.Size(); i++) {
// For each interval of the refinement partition...
rp.Get(i, interval, aPos, bPos);
Periods intervalAsPeriod(1);
intervalAsPeriod.Add(interval);
aIsEmpty = (aPos == -1);
bIsEmpty = (bPos == -1);
assert(!(aIsEmpty && bIsEmpty));
if (aIsEmpty || bIsEmpty) {
if (op == INTERSECTION) {
// Result is empty: nothing to do.
continue;
}
if (op == MINUS && aIsEmpty) {
// Result is empty: nothing to do.
continue;
}
}
if (!aIsEmpty) {
a->Get(aPos, unitA);
tempA = new MRegion(1);
tempA->AtPeriods(&intervalAsPeriod, a);
tempA->Get(0, unitARestrict);
aArray = tempA->GetMSegmentData();
unitARestrictCopy = new URegionEmb(unitARestrict.timeInterval,
unitARestrict.GetStartPos());
unitARestrictCopy->SetSegmentsNum(unitARestrict.GetSegmentsNum());
unitARestrictCopy->SetBBox(unitARestrict.BoundingBox());
}
if (!bIsEmpty) {
b->Get(bPos, unitB);
tempB = new MRegion(1);
tempB->AtPeriods(&intervalAsPeriod, b);
tempB->Get(0, unitBRestrict);
bArray = tempB->GetMSegmentData();
unitBRestrictCopy = new URegionEmb(unitBRestrict.timeInterval,
unitBRestrict.GetStartPos());
unitBRestrictCopy->SetSegmentsNum(unitBRestrict.GetSegmentsNum());
unitBRestrictCopy->SetBBox(unitBRestrict.BoundingBox());
}
so = new SourceUnitPair(unitARestrictCopy, aArray, aIsEmpty,
unitBRestrictCopy, bArray, bIsEmpty,
op,
res);
so->Operate();
delete so;
if (!aIsEmpty) {
delete tempA;
delete unitARestrictCopy;
}
if (!bIsEmpty) {
delete tempB;
delete unitBRestrictCopy;
}
}
res->EndBulkLoad(false);
#ifdef PRINT_STATISTIC
statistic.noUnitsResult = res->GetNoComponents();
statistic.Print();
#endif
}
/*
1 Class SourceUnit
*/
SourceUnit::SourceUnit(const bool _isUnitA,
URegionEmb* const _uRegion,
const DbArray<MSegmentData>* _array,
const bool _isEmpty,
SourceUnitPair* const _parent) :
isUnitA(_isUnitA),
isEmpty(_isEmpty),
uRegion(_uRegion),
array(_array),
parent(_parent),
hasNormalizedTimeInterval(false) {
if (_isEmpty)
return;
originalTimeInterval = _uRegion->timeInterval;
NormalizeTimeInterval();
ComputeBoundingRect();
startTime = _uRegion->timeInterval.start.ToDouble();
endTime = _uRegion->timeInterval.end.ToDouble();
}
SourceUnit::~SourceUnit() {
vector<PFace*>::iterator iter;
for (iter = pFaces.begin(); iter != pFaces.end(); iter++) {
delete *iter;
}
}
void SourceUnit::NormalizeTimeInterval() {
if (!NORMALIZE_TIME_INTERVAL_OF_SOURCE_UNITS)
return;
//cout << "timeInterval.start: " << uRegion->timeInterval.start << endl;
//cout << "timeInterval.end: " << uRegion->timeInterval.end << endl;
//const double scaledDelta = 1.0;
const double delta =
(originalTimeInterval.end - originalTimeInterval.start).ToDouble();
//cout << "delta: " << delta << endl;
if (delta >= 1.0) {
hasNormalizedTimeInterval = false;
return;
}
hasNormalizedTimeInterval = true;
uRegion->timeInterval.start.SetToZero();
uRegion->timeInterval.end.ReadFrom(1.0);
// Adjust the bounding box:
const double minX = uRegion->BoundingBox().MinD(0);
const double maxX = uRegion->BoundingBox().MaxD(0);
const double minY = uRegion->BoundingBox().MinD(1);
const double maxY = uRegion->BoundingBox().MaxD(1);
const double minT = 0.0;
const double maxT = 1.0;
double minMax[] = { minX, maxX, minY, maxY, minT, maxT};
uRegion->SetBBox(Rectangle<3>(true,minMax ));
//scaleFactor = delta / scaledDelta;
//scaleFactor = delta;
//cout << "scaleFactor: " << scaleFactor << endl;
//cout << "timeInterval.start: " << uRegion->timeInterval.start << endl;
//cout << "timeInterval.end: " << uRegion->timeInterval.end << endl;
}
void SourceUnit::ComputeBoundingRect() {
// Calculate the projection bounding rectangle in the (x, y)-plane
// of the URegion:
const double minX = uRegion->BoundingBox().MinD(0);
const double maxX = uRegion->BoundingBox().MaxD(0);
const double minY = uRegion->BoundingBox().MinD(1);
const double maxY = uRegion->BoundingBox().MaxD(1);
double minMax[] = { minX, maxX, minY, maxY};
boundingRect = Rectangle<2>(true,minMax );
}
void SourceUnit::CreatePFaces() {
MSegmentData segment;
for (int i = 0; i < uRegion->GetSegmentsNum(); i++) {
uRegion->GetSegment(array, i, segment);
PFace* pFace = new PFace(this, &segment);
pFaces.push_back(pFace);
#ifdef OPTIMIZE_BY_BOUNDING_RECT
if (parent->HasOverlappingBoundingRect()) {
if (pFace->GetBoundingRect().Intersects(parent->GetOverlapRect()))
pFacesReduced.push_back(pFace);
else
pFace->MarkAsEntirelyOutside();
} else {
pFace->MarkAsEntirelyOutside();
pFacesReduced.push_back(pFace);
}
#else
pFacesReduced.push_back(pFace);
#endif
}
statistic.noPFaceTotal += pFaces.size();
statistic.noPFaceReducedByPBR += pFacesReduced.size();
}
void SourceUnit::CollectRelevantPFaces(ResultUnitFactory* receiver) {
vector<PFace*>::iterator iter;
for (iter = pFaces.begin(); iter != pFaces.end(); iter++) {
(*iter)->Finalize();
assert((*iter)->GetState() != UNKNOWN);
assert((*iter)->GetState() != ENTIRELY_INSIDE);
assert((*iter)->GetState() != ENTIRELY_OUTSIDE);
if ((*iter)->IsNormalRelevant() || (*iter)->IsCriticalRelevant()) {
receiver->AddPFace(*iter);
}
}
}
void SourceUnit::PrintPFaces() {
for (vector<PFace*>::iterator iter = pFaces.begin();
iter != pFaces.end(); iter++) {
(*iter)->Print();
}
}
void SourceUnit::Print() const {
cout << ((IsUnitA()) ? "Unit A:" : "Unit B:") << endl;
cout << "Interval: " << GetTimeInterval() << endl;
cout << "Interval as double: " << GetTimeInterval().start.ToDouble()
<< " -> " << GetTimeInterval().end.ToDouble() << endl;
cout << "No of PFaces total: " << pFaces.size() << endl;
cout << "No of PFaces reduced: " << pFacesReduced.size() << endl;
}
void SourceUnit::PrintVRMLDesc(ofstream& target, const string& color) {
const double scale = VRML_SCALE_FACTOR;
target << "Transform {" << endl;
target << "\tscale " << scale << " " << scale << " " << scale << endl;
target << "\tchildren [" << endl;
target << "\t\tShape {" << endl;
target << "\t\t\tgeometry IndexedLineSet {" << endl;
target << "\t\t\t\tcoord Coordinate {" << endl;
target << "\t\t\t\t\tpoint [" << endl;
int pFaceCount = 0;
for (vector<PFace*>::iterator iter = pFaces.begin();
iter != pFaces.end(); iter++) {
target << "\t\t\t\t\t\t" << (*iter)->GetVRMLDesc() << endl;
pFaceCount++;
}
target << "\t\t\t\t\t] # end point" << endl;
target << "\t\t\t\t} # end coord" << endl;
target << "\t\t\t\tcoordIndex [" << endl;
const int noPoints = pFaceCount * 4;
for (int i = 0; i < noPoints; i += 4) {
target << "\t\t\t\t\t" << i << ", " << i + 1 << ", " << i + 2 << ", "
<< i + 3 << ", " << i << ", " << "-1," << endl;
}
target << "\t\t\t\t] # end coordIndex" << endl;
target << "\t\t\t\tcolor Color { color [ " << color << " ] }" << endl;
target << "\t\t\t} # end geometry" << endl;
target << "\t\t} # end shape" << endl;
target << "\t] # end children" << endl;
target << "} # end Transform" << endl;
}
bool SourceUnit::IsEntirelyOutside(const PFace* pFace) {
// Precondition: pFace is known as entirely inside or entirely outside!
// Check, if the answer is already known:
if (pFace->IsEntirelyOutside())
return true;
if (pFace->IsEntirelyInside())
return false;
// We don't know and have to use the plumbline algorithm
// to find the answer:
assert(pFace->GetState() == UNKNOWN);
return IsOutside(pFace->GetMidPoint());
}
bool SourceUnit::IsOutside(const Point3D& p) {
const Point p2D(true, p.GetX(), p.GetY());
return !GetTestRegion(p.GetT()).Contains(p2D);
}
bool SourceUnit::IsOnBorder(const Point3D& p) {
const Point p2D(true, p.GetX(), p.GetY());
if (GetTestRegion(p.GetT()).OnBorder(p2D)) {
return true;
}
// This is not very nice, maybe sometimes even wrong...
// It is necessary, since Region::OnBorder may
// return false-negative results, because of rounding errors.
// We paint a 'small' triangle around p and check,
// if it intersects the testregion's border.
const double d = NumericUtil::eps * 100;
const Point p1(true, p.GetX() - d, p.GetY() - d);
const Point p2(true, p.GetX() + d, p.GetY() - d);
const Point p3(true, p.GetX(), p.GetY() + d);
const bool p1IsInside = GetTestRegion(p.GetT()).Contains(p1);
const bool p2IsInside = GetTestRegion(p.GetT()).Contains(p2);
const bool p3IsInside = GetTestRegion(p.GetT()).Contains(p3);
const int sum = p1IsInside + p2IsInside + p3IsInside;
if (sum == 0 || sum == 3) {
// The triangle is entirely outside or inside the testregion:
return false;
} else { // sum == 1 || sum == 2
// The triangle intersects the testregion's border:
return true;
}
}
#ifdef CACHE_TESTREGIONS
const Region SourceUnit::GetTestRegion(const double t) {
Instant instant(instanttype);
instant.ReadFrom(t);
if (!testRegion.defined || testRegion.instant != instant) {
//cout << "Create new TestRegion at instant: " << instant << endl;
statistic.NoTestRegionsCreated++;
Region newTestRegion(0);
GetURegionEmb()->TemporalFunction(array, instant, newTestRegion);
testRegion.instant = instant;
testRegion.region = newTestRegion;
testRegion.defined = true;
} else {
//cout << "TestRegion cachehit at instant: " << instant << endl;
statistic.NoTestRegionsCacheHits++;
}
return testRegion.region;
}
#else
const Region SourceUnit::GetTestRegion(const double t) {
Instant instant(instanttype);
instant.ReadFrom(t);
Region testRegion(0);
GetURegionEmb()->TemporalFunction(array, instant, testRegion);
return testRegion;
}
#endif
const SetOp SourceUnit::GetOperation() const {
return parent->GetOperation();
}
void SourceUnit::AddGlobalTimeValue(double t) {
parent->AddGlobalTimeValue(t);
}
void SourceUnit::AddToMRegion(MRegion* const target) const {
if (IsEmpty())
return;
DbArray<MSegmentData>* targetArray =
(DbArray<MSegmentData>*)target->GetFLOB(1);
const int segmentsStartPos = targetArray->Size();
URegionEmb targetUnit(GetOriginalTimeInterval(), segmentsStartPos);
MSegmentData segment;
for (int i = 0; i < uRegion->GetSegmentsNum(); i++) {
uRegion->GetSegment(array, i, segment);
targetUnit.PutSegment(targetArray, i, segment, true);
}
target->Add(targetUnit);
}
/*
1 Class ResultUnitFactory
*/
void ResultUnitFactory::Start() {
if (time.size() < 2) {
// Result is empty.
return;
}
// Set the first initial timelevel:
timeIter = time.begin();
t1 = *timeIter;
while ((++timeIter) != time.end()) {
// Set the final timelevel:
t2 = *timeIter;
// Set the median timelevel:
t12 = (t1 + t2) / 2.0;
ComputeCurrentTimeLevel();
// Set the new initial timelevel:
t1 = t2;
}
}
void ResultUnitFactory::ComputeCurrentTimeLevel() {
//cout << "t1: " << t1 << endl;
//cout << "t12: " << t12 << endl;
//cout << "t2: " << t2 << endl;
assert(NumericUtil::Lower(t1, t2));
Instant starttime(instanttype);
Instant endtime(instanttype);
if (parent->HasNormalizedTimeInterval()) {
const double originalStart =
parent->GetOriginalTimeInterval().start.ToDouble();
const double originalEnd =
parent->GetOriginalTimeInterval().end.ToDouble();
starttime.ReadFrom((1.0 - t1) * originalStart + t1 * originalEnd);
endtime.ReadFrom((1.0 - t2) * originalStart + t2 * originalEnd);
} else {
starttime.ReadFrom(t1);
endtime.ReadFrom(t2);
}
const Interval<Instant> interval(starttime, endtime, true, false);
//cout << "start: " << starttime.ToDouble() << endl;
//cout << "end: " << endtime.ToDouble() << endl;
resultUnit = new ResultUnit(interval);
resultUnit->StartBulkLoad();
vector<PFace*>::iterator iter;
for (iter = pFaces.begin(); iter != pFaces.end(); iter++) {
PFace* pFace = *iter;
//pFace->Print();
pFace->UpdateTimeLevel(t1);
if (pFace->IsNormalRelevant()) {
ProcessNormalPFace(pFace);
} else { // pFace->IsCriticalRelevant()
ProcessCriticalPFace(pFace);
}
}
//cout << "ResultUnit: " << t1 << " -> " << t2 << endl;
//Instant mediantime(instanttype);
//mediantime.ReadFrom(t12);
//cout << "mediantime: " << mediantime.ToString() << endl;
AddCriticalMSegments();
//cout << "ResultUnit: " << t1 << " -> " << t2 << endl;
//assert(false);
//cout << endl;
//cout << "ResultUnit: " << t1 << " -> " << t2 << endl;
//cout << endl;
//resultUnit->WriteToVRMLFile();
//this->Print();
resultUnit->EndBulkLoad(MERGE_RESULT_MSEGMENTS);
ConstructResultUnitAsURegionEmb();
delete resultUnit;
}
void ResultUnitFactory::ProcessNormalPFace(PFace* pFace) {
//assert(NumericUtil::Lower(t1, t2));
#ifdef PRINT_STATISTIC
StopWatch stopWatch;
stopWatch.start();
#endif
const list<IntersectionSegment*>* intSegs;
list<IntersectionSegment*>::const_iterator intSegIter;
Decision decision;
Decision lastDecision = pFace->GetLastDecision();
bool firstMSegInTimeLevel = true;
intSegs = pFace->GetActiveIntSegs();
intSegIter = intSegs->begin();
assert(intSegs->size() >= 2);
const IntersectionSegment* start = *intSegIter;
const IntersectionSegment* end;
Point3D initialStart3D(start->Evaluate(t1));
Point3D mediumStart3D(start->Evaluate(t12));
Point3D finalStart3D(start->Evaluate(t2));
while ((++intSegIter) != intSegs->end()) {
end = *intSegIter;
evalutedIntSegs++;
Point3D initialEnd3D(end->Evaluate(t1));
Point3D mediumEnd3D(end->Evaluate(t12));
Point3D finalEnd3D(end->Evaluate(t2));
Segment3D initial(initialStart3D, initialEnd3D);
Segment3D medium(mediumStart3D, mediumEnd3D);
Segment3D final(finalStart3D, finalEnd3D);
if (mediumStart3D == mediumEnd3D) {
decisionsByDegeneration++;
cout << "Warning: Degenerated MSegment in normal PFace found!"
<< endl;
cout << "This should never happen..." << endl;
cout << "initial: " << initial << endl;
cout << "medium: " << medium << endl;
cout << "final" << final << endl;
start = end;
continue;
}
if (lastDecision == UNDEFINED || DECIDE_BY_PLUMBLINE_ONLY) {
Point3D midpoint3D((mediumStart3D + mediumEnd3D) * 0.5);
decision = BelongsToResultUnit(midpoint3D, pFace);
if (firstMSegInTimeLevel) {
pFace->SetLastDecision(decision);
firstMSegInTimeLevel = false;
}
} else { // lastDecision != UNDEFINED
decisionsByAdjacency++;
if (firstMSegInTimeLevel) {
decision = lastDecision;
pFace->SetLastDecision(decision);
firstMSegInTimeLevel = false;
} else {
if (lastDecision == ACCEPT)
decision = SKIP;
else
decision = ACCEPT;
}
}
switch (decision) {
case SKIP:
// This msegment does not contribute to the result.
noMSegsSkipped++;
break;
case ACCEPT:
// This msegment contributes to the result.
resultUnit->AddSegment(MSegment(initial, medium, final, pFace));
noMSegsValid++;
break;
case UNDEFINED:
// This case should never occur:
assert(false);
break;
}
start = end;
initialStart3D = initialEnd3D;
mediumStart3D = mediumEnd3D;
finalStart3D = finalEnd3D;
lastDecision = decision;
}
#ifdef PRINT_STATISTIC
statistic.durationProcessNormalPFace += stopWatch.diffSecondsReal();
#endif
}
void ResultUnitFactory::ProcessCriticalPFace(PFace* pFace) {
//assert(NumericUtil::Lower(t1, t2));
#ifdef PRINT_STATISTIC
StopWatch stopWatch;
stopWatch.start();
#endif
const list<IntersectionSegment*>* intSegs;
list<IntersectionSegment*>::const_iterator intSegIter;
Decision decision;
intSegs = pFace->GetActiveIntSegs();
intSegIter = intSegs->begin();
assert(intSegs->size() >= 2);
const IntersectionSegment* start = *intSegIter;
const IntersectionSegment* end;
Point3D initialStart3D(start->Evaluate(t1));
Point3D mediumStart3D(start->Evaluate(t12));
Point3D finalStart3D(start->Evaluate(t2));
while ((++intSegIter) != intSegs->end()) {
end = *intSegIter;
evalutedIntSegs++;
Point3D initialEnd3D(end->Evaluate(t1));
Point3D mediumEnd3D(end->Evaluate(t12));
Point3D finalEnd3D(end->Evaluate(t2));
Point3D midpoint3D((mediumStart3D + mediumEnd3D) * 0.5);
Segment3D initial(initialStart3D, initialEnd3D);
Segment3D medium(mediumStart3D, mediumEnd3D);
Segment3D final(finalStart3D, finalEnd3D);
//cout << "initial: " << initial << endl;
//cout << "medium: " << medium << endl;
//cout << "final: " << final << endl;
//cout << "midpoint3D: " << midpoint3D << endl;
if (mediumStart3D == mediumEnd3D) {
decisionsByDegeneration++;
decision = SKIP;
} else {
decision = BelongsToResultUnit(midpoint3D, pFace);
}
switch (decision) {
case SKIP:
// This msegment does not contribute to the result.
noMSegsSkipped++;
//cout << "decision: SKIP" << endl;
break;
case ACCEPT:
// This msegment contributes to the result.
resultUnit->AddSegment(MSegment(initial, medium, final, pFace));
noMSegsValid++;
//cout << "decision: ACCEPT" << endl;
break;
case UNDEFINED:
// This msegment is part of a pair of identical ones
// and we can't do a decision now.
criticalMSegs.push_back(MSegmentCritical(initial, medium, final,
midpoint3D, pFace));
noMSegCritical++;
//cout << "decision: UNDEFINED" << endl;
break;
}
//cout << endl;
start = end;
initialStart3D = initialEnd3D;
mediumStart3D = mediumEnd3D;
finalStart3D = finalEnd3D;
}
#ifdef PRINT_STATISTIC
statistic.durationProcessCriticalPFace += stopWatch.diffSecondsReal();
#endif
}
Decision ResultUnitFactory::BelongsToResultUnit(const Point3D& midpoint,
const PFace* pFace) {
if (DECIDE_BY_ENTIRELY_IN_OUT &&
pFace->IsNormalRelevant() &&
!pFace->HasInnerIntSegs()) {
decisionsByEntirelyInOut++;
return ACCEPT;
}
const SourceUnit* ownUnit = pFace->GetUnit();
SourceUnit* otherUnit = ownUnit->GetPartner();
const SetOp op = parent->GetOperation();
decisionsByPlumbline++;
if (pFace->IsCriticalRelevant() && otherUnit->IsOnBorder(midpoint)) {
// The testpoint is on the border of the testregion.
// Hence we can decide it not yet:
return UNDEFINED;
}
if (otherUnit->IsOutside(midpoint)) {
if (op == UNION || (op == MINUS && ownUnit->IsUnitA()))
return ACCEPT;
else
return SKIP;
}
// The Point is inside of otherUnit.
if (op == INTERSECTION || (op == MINUS && ownUnit->IsUnitB()))
return ACCEPT;
else
return SKIP;
}
void ResultUnitFactory::AddCriticalMSegments() {
if (criticalMSegs.size() == 0)
return;
// Sort by midpoints:
sort(criticalMSegs.begin(), criticalMSegs.end());
const SetOp op = parent->GetOperation();
//cout << "criticalMSegs.size() = " << criticalMSegs.size() << endl;
//for (unsigned int i = 0; i < criticalMSegs.size(); i++) {
//criticalMSegs[i].Print();
//cout << "midpoint: ";
//cout << criticalMSegs[i].GetMidpoint().GetX() << " | " <<
//criticalMSegs[i].GetMidpoint().GetY() << endl;
//}
assert(criticalMSegs.size() % 2 == 0);
for (unsigned int i = 0; i < criticalMSegs.size(); i += 2) {
MSegmentCritical mSeg1 = criticalMSegs[i];
MSegmentCritical mSeg2 = criticalMSegs[i + 1];
//cout << "mSeg1.GetMidpoint(): " << mSeg1.GetMidpoint() << endl;
//cout << "mSeg2.GetMidpoint(): " << mSeg2.GetMidpoint() << endl;
assert(mSeg1.GetMidpoint() == mSeg2.GetMidpoint());
if (op == UNION || op == INTERSECTION) {
if (!mSeg1.HasEqualNormalVector(mSeg2)) {
// Skip both.
noMSegsSkipped++;
noMSegsSkipped++;
} else { // HasEqualNormalVector(other)
if (mSeg1.IsPartOfUnitA())
resultUnit->AddSegment(mSeg1);
else
resultUnit->AddSegment(mSeg2);
noMSegsValid++;
noMSegsSkipped++;
}
} else { // op == MINUS
if (mSeg1.HasEqualNormalVector(mSeg2)) {
// Skip both.
noMSegsSkipped++;
noMSegsSkipped++;
} else { // !HasEqualNormalVector(other)
if (mSeg1.IsPartOfUnitA())
resultUnit->AddSegment(mSeg1);
else
resultUnit->AddSegment(mSeg2);
noMSegsValid++;
noMSegsSkipped++;
}
}
}
criticalMSegs.clear();
}
void ResultUnitFactory::ConstructResultUnitAsURegionEmb() {
if (resultUnit->IsEmpty()) {
noEmptyUnits++;
return;
}
noUnits++;
//cout << "ResultUnit created: " << resultUnit->GetInterval() << endl;
//cout << endl;
#ifdef WRITE_VRML_FILE
vrml.push_back(resultUnit->GetVRMLDesc());
#endif
const Interval<Instant> interval = resultUnit->GetInterval();
DbArray<MSegmentData>* array =
(DbArray<MSegmentData>*)resMRegion->GetFLOB(1);
URegionEmb* ure = resultUnit->ConvertToURegionEmb(array);
//cout << NList(resultUnit->ConvertToListExpr()) << endl;
resMRegion->Add(*ure);
delete ure;
}
void ResultUnitFactory::Print() const {
cout << "ResultUnitFactory: " << endl;
cout << "Units created: " << noUnits << endl;
cout << "Empty units: " << noEmptyUnits << endl;
cout << "Processed PFaces total: " << pFaces.size() << endl;
cout << "MSegments total: " << evalutedIntSegs << endl;
cout << "MSegments valid: " << noMSegsValid << endl;
cout << "MSegments skipped: " << noMSegsSkipped << endl;
cout << "MSegments critical: " << noMSegCritical << endl;
cout << "Decisions by plumbline: " << decisionsByPlumbline << endl;
cout << "Decisions by entirely inside/outside: " <<
decisionsByEntirelyInOut << endl;
cout << "Decisions by adjacency: " << decisionsByAdjacency << endl;
cout << "Decisions by degeneration: " << decisionsByDegeneration << endl;
cout << endl;
}
string ResultUnitFactory::GetVRMLDesc() const {
std::ostringstream oss;
for (unsigned int i = 0; i < vrml.size(); i++) {
oss << vrml[i] << endl;
}
return oss.str();
}
void ResultUnitFactory::AddToOverallStatistic() const {
statistic.noRelevantPFaces += pFaces.size();
statistic.noMSegsOverall += evalutedIntSegs;
statistic.noMSegsValidOverall += noMSegsValid;
statistic.noMSegsSkippedOverall += noMSegsSkipped;
statistic.noMSegCriticalOverall += noMSegCritical;
statistic.decisionsByPlumblineOverall += decisionsByPlumbline;
statistic.decisionsByEntirelyInOutOverall += decisionsByEntirelyInOut;
statistic.decisionsByAdjacencyOverall += decisionsByAdjacency;
statistic.decisionsByDegenerationOverall += decisionsByDegeneration;
}
/*
1 Class SourceUnitPair
*/
SourceUnitPair::SourceUnitPair(URegionEmb* const _unitA,
const DbArray<MSegmentData>* const _aArray,
const bool _aIsEmpty,
URegionEmb* const _unitB,
const DbArray<MSegmentData>* const _bArray,
const bool _bIsEmpty,
const SetOp _operation,
MRegion* const _resultMRegion) :
unitA(true, _unitA, _aArray, _aIsEmpty, this),
unitB(false, _unitB, _bArray, _bIsEmpty, this),
op(_operation),
resultMRegion(_resultMRegion),
resultUnitFactory(_resultMRegion, this) {
if (_aIsEmpty || _bIsEmpty)
return;
assert(_unitA->timeInterval == _unitB->timeInterval);
unitA.SetPartner(&unitB);
unitB.SetPartner(&unitA);
ComputeOverlapRect();
//cout << "SourceUnitPair with interval " << GetOriginalTimeInterval()
//<< " created." << endl;
#ifdef PRINT_DEBUG_MESSAGES
if (HasNormalizedTimeInterval())
cout << "Interval was normalized to: " << GetTimeInterval()
<< endl;
#endif
}
void SourceUnitPair::Operate() {
#ifdef OPTIMIZE_BY_BOUNDING_RECT
const bool s = false;
#else
const bool s = true;
#endif
if ((!unitA.IsEmpty() && !unitB.IsEmpty()) &&
(s || op == UNION || HasOverlappingBoundingRect())) {
#ifdef PRINT_STATISTIC
StopWatch stopWatch;
stopWatch.start();
#endif
CreatePFaces();
#ifdef PRINT_STATISTIC
statistic.durationCreatePFacesOverall += stopWatch.diffSecondsReal();
#endif
#ifdef PRINT_DEBUG_MESSAGES
cout << "*************************************************************";
cout << endl;
cout << "PFaces after calling CreatePFaces():" << endl;
cout << endl;
PrintPFaces();
#endif
#ifdef PRINT_STATISTIC
stopWatch.start();
#endif
ComputeIntSegs();
#ifdef PRINT_STATISTIC
statistic.durationComputeIntSegsOverall += stopWatch.diffSecondsReal();
#endif
#ifdef PRINT_DEBUG_MESSAGES
cout << "*************************************************************";
cout << endl;
cout << "PFaces after calling ComputeIntSegs():" << endl;
cout << endl;
PrintPFaces();
#endif
#ifdef PRINT_STATISTIC
stopWatch.start();
#endif
CollectRelevantPFaces();
#ifdef PRINT_STATISTIC
statistic.durationCollectRelevantPFacesOverall
+= stopWatch.diffSecondsReal();
#endif
#ifdef PRINT_DEBUG_MESSAGES
cout << "*************************************************************";
cout << endl;
cout << "PFaces after calling CollectRelevantPFaces():" << endl;
cout << endl;
PrintPFaces();
#endif
#ifdef PRINT_STATISTIC
stopWatch.start();
#endif
ConstructResultUnits();
#ifdef PRINT_STATISTIC
statistic.durationConstructResultUnitsOverall
+= stopWatch.diffSecondsReal();
resultUnitFactory.AddToOverallStatistic();
#endif
#ifdef WRITE_VRML_FILE
ToVrmlFile(showSourceUnitA, showSourceUnitB, showResultUnits);
#endif
} else {
// unitA.IsEmpty() || unitB.IsEmpty() ||
// (!s && op != UNION && !HasOverlappingBoundingRect())
switch (op) {
case MINUS:
// Result is unit a:
unitA.AddToMRegion(resultMRegion);
break;
case INTERSECTION:
// Result is empty:
// Nothing to do.
break;
case UNION:
assert(unitA.IsEmpty() || unitB.IsEmpty());
unitA.AddToMRegion(resultMRegion);
unitB.AddToMRegion(resultMRegion);
break;
}
}
}
void SourceUnitPair::ComputeOverlapRect() {
overlapRect = unitA.GetBoundingRect().Intersection(unitB.GetBoundingRect());
}
void SourceUnitPair::CreatePFaces() {
unitA.CreatePFaces();
unitB.CreatePFaces();
}
void SourceUnitPair::ComputeIntSegs() {
vector<PFace*>::iterator iterA;
vector<PFace*>::iterator iterB;
for (iterA = unitA.pFacesReduced.begin(); iterA
!= unitA.pFacesReduced.end(); iterA++) {
for (iterB = unitB.pFacesReduced.begin(); iterB
!= unitB.pFacesReduced.end(); iterB++) {
(*iterA)->Intersection(**iterB);
}
}
}
void SourceUnitPair::CollectRelevantPFaces() {
unitA.CollectRelevantPFaces(&resultUnitFactory);
unitB.CollectRelevantPFaces(&resultUnitFactory);
}
void SourceUnitPair::ConstructResultUnits() {
resultUnitFactory.Start();
}
void SourceUnitPair::PrintPFaces() {
cout << endl;
cout << "*********************************************" << endl;
cout << "PFaces of Unit A:" << endl;
cout << "*********************************************" << endl;
cout << endl;
unitA.PrintPFaces();
cout << endl;
cout << "*********************************************" << endl;
cout << "PFaces of Unit B:" << endl;
cout << "*********************************************" << endl;
cout << endl;
unitB.PrintPFaces();
}
void SourceUnitPair::ToVrmlFile(bool a, bool b, bool res) {
if (!a && !b && !res)
return;
const string colorA = "1 1 0";
const string colorB = "0 0.6 1";
//const string colorResult = "1 0 0";
const string filename = "unitpair_" +
GetTimeInterval().start.ToString() +
".wrl";
ofstream target(filename.c_str());
if (!target.is_open()) {
cerr << "Unable to open file: " << filename << endl;
return;
}
target << "#VRML V2.0 utf8" << endl;
if (a) {
target << endl;
target << "# Unit A:" << endl;
target << endl;
unitA.PrintVRMLDesc(target, colorA);
}
if (b) {
target << endl;
target << "# Unit B:" << endl;
target << endl;
unitB.PrintVRMLDesc(target, colorB);
}
if (res) {
target << endl;
target << "# Result units:" << endl;
target << endl;
target << resultUnitFactory.GetVRMLDesc() << endl;
}
target.close();
}
/*
1 Class IntersectionSegment
*/
unsigned int IntersectionSegment::instanceCount = 0;
IntersectionSegment::IntersectionSegment(const Segment3D& s) :
id(instanceCount++),
pFace(0) {
// The startpoint's t-coord is always lower or equal to the
// endpoint's t-coord.
// Note: We don't care for x and y!
if (s.GetStart().GetT() <= s.GetEnd().GetT()) {
startXYT = s.GetStart();
endXYT = s.GetEnd();
} else {
startXYT = s.GetEnd();
endXYT = s.GetStart();
}
statistic.noIntSegsTotal++;
}
bool IntersectionSegment::IsLeftOf(const IntersectionSegment* intSeg) const {
// Precondition:
// this->GetStartT() is inside the interval
// [intSeg->GetStartT(), intSeg->GetEndT()]
// and
// this and intSeg don't intersect in their interior.
assert(NumericUtil::GreaterOrNearlyEqual(this->GetStartT(),
intSeg->GetStartT())
&&
NumericUtil::LowerOrNearlyEqual(this->GetStartT(),
intSeg->GetEndT()));
//const double eps = NumericUtil::eps * 100;
const double eps = NumericUtil::eps;
const double sideOfStart = GetStartWT()->WhichSide(*intSeg->GetStartWT(),
*intSeg->GetEndWT());
if (sideOfStart > eps)
return true;
if (sideOfStart < -eps)
return false;
const double sideOfEnd = GetEndWT()->WhichSide(*intSeg->GetStartWT(),
*intSeg->GetEndWT());
return sideOfEnd > eps;
}
void IntersectionSegment::SetWCoords() {
SetStartWT(GetPFace()->TransformToWT(*GetStartXYT()));
SetEndWT(GetPFace()->TransformToWT(*GetEndXYT()));
}
Point3D IntersectionSegment::Evaluate(const double t) const {
// We compute the intersection point
// of the horizontal plane, defined by t, and this segment.
// Precondition:
// t is between t_start and t_end.
assert(NumericUtil::Between(GetStartT(), t, GetEndT()));
// Point3D pointInPlane(0.0, 0.0, t);
// Vector3D normalVectorOfPlane(0.0, 0.0, 1.0);
// Vector3D u = *this->GetEndXYT() - *this->GetStartXYT();
// Vector3D w = this->GetStartXYT() - pointInPlane;
// double d = normalVectorOfPlane * u;
// double n = -normalVectorOfPlane * w;
// This can be simplified to:
const Vector3D u = *GetEndXYT() - *GetStartXYT();
const double d = GetEndT() - GetStartT();
const double n = t - GetStartT();
// This segment must not be parallel to plane:
assert(!NumericUtil::NearlyEqual(d, 0.0));
const double s = n / d;
// This segment intersects the plane:
assert(NumericUtil::Between(0.0, s, 1.0));
// Compute segment intersection point:
return *GetStartXYT() + s * u;
}
void IntersectionSegment::Print() const {
cout << "ID: " << GetID() << " ";
cout << *GetStartXYT() << " -> " << *GetEndXYT();
//cout << *GetStartWT() << " -> " << *GetEndWT();
}
string IntersectionSegment::GetVRMLDesc() {
return GetStartXYT()->GetVRMLDesc() + GetEndXYT()->GetVRMLDesc();
}
/*
1 Class MSegment
*/
MSegment::MSegment(const Segment3D& _initial,
const Segment3D& _median,
const Segment3D& _final,
const PFace* const _pFace) :
initial(_initial),
median(_median),
final(_final),
pFace(_pFace) {
assert(pFace->IsCoplanarTo(_initial));
assert(pFace->IsCoplanarTo(_median));
assert(pFace->IsCoplanarTo(_final));
assert(!(initial.GetStart() == initial.GetEnd() && final.GetStart()
== final.GetEnd()));
//assert(initial.IsParallel(final));
// Create and init the median halfsegment:
Point m1(true, _median.GetStart().GetX(), _median.GetStart().GetY());
Point m2(true, _median.GetEnd().GetX(), _median.GetEnd().GetY());
medianHS = HalfSegment(true, m1, m2);
insideAbove = medianHS.attr.insideAbove = m1 > m2;
medianHS.attr.faceno = -1;
medianHS.attr.cycleno = -1;
medianHS.attr.edgeno = -1;
medianHS.attr.coverageno = -1;
medianHS.attr.partnerno = -1;
}
bool MSegment::IsParallel(const MSegment& ms) const {
return GetPFace()->IsParallelTo(*ms.GetPFace());
}
void MSegment::Print() const {
cout << "start: " << NList(GetStartAsListExpr()) << endl;
cout << "end: " << NList(GetEndAsListExpr()) << endl;
cout << "median: " << this->GetMedianHS() << endl;
cout << " F: " << GetFaceNo();
cout << " C: " << GetCycleNo();
cout << " S: " << GetSegmentNo();
cout << " LDP: " << GetMedianHS().IsLeftDomPoint() << endl;
}
/*
1 Class MSegmentCritical
*/
bool MSegmentCritical::IsPartOfUnitA() const {
return GetPFace()->IsPartOfUnitA();
}
bool MSegmentCritical::HasEqualNormalVector(const MSegmentCritical& msc) const {
return GetPFace()->HasEqualNormalVector(*msc.GetPFace());
}
/*
1 Class ResultUnit
*/
void ResultUnit::EndBulkLoad(bool merge) {
#ifdef PRINT_STATISTIC
StopWatch stopWatch;
stopWatch.start();
#endif
if (IsEmpty())
return;
// First, we sort the msegments of this unit by their
// median-halfsegments. Comparison between halfsegments
// is done by the < operator, implemented in the SpatialAlgebra.
sort(msegments.begin(), msegments.end(), ResultUnit::Less);
// Second, we construct a region from all median-halfsegments
// of each msegment of this unit:
Region r(msegments.size());
r.StartBulkLoad();
for (unsigned int i = 0; i < msegments.size(); i++) {
//cout << msegments[i].GetMedianHS() << endl;
r.Put(i, msegments[i].GetMedianHS());
}
// Note: Sorting is already done.
r.EndBulkLoad(false, true, true, true);
// Third, we retrive the faceNo, cycleNo and edgeNo of
// each halfsegment from the region, computed in the
// Region::EndBulkLoad procedure:
for (unsigned int i = 0; i < msegments.size(); i++) {
HalfSegment hs;
r.Get(i, hs);
msegments[i].CopyIndicesFrom(&hs);
}
// Sort msegments by faceno, cycleno and segmentno:
sort(msegments.begin(), msegments.end(), ResultUnit::LogicLess);
//this->Print();
// Erase the second half of msegments,
// which contains all MSegments with right dominating point:
msegments.erase(msegments.begin() + msegments.size() / 2, msegments.end());
if (merge) {
// Not implemented yet.
}
//this->Print();
#ifdef PRINT_STATISTIC
statistic.durationEndBulkloadOfResultUnit += stopWatch.diffSecondsReal();
#endif
}
const ListExpr ResultUnit::ConvertToListExpr() const {
const int num = msegments.size();
ListExpr faces = nl->TheEmptyList();
ListExpr facesLastElem = faces;
ListExpr face = nl->TheEmptyList();
ListExpr faceLastElem = face;
ListExpr cycle = nl->TheEmptyList();
ListExpr cycleLastElem = cycle;
for (int i = 0; i < num; i++) {
const MSegment* dms = &msegments[i];
const MSegment* nextDms;
ListExpr p = dms->GetStartAsListExpr();
if (cycle == nl->TheEmptyList()) {
cycle = nl->OneElemList(p);
cycleLastElem = cycle;
} else {
cycleLastElem = nl->Append(cycleLastElem, p);
}
if (i < num - 1) {
nextDms = &msegments[i + 1];
}
if (i == num - 1 || dms->GetCycleNo() != nextDms->GetCycleNo()
|| dms->GetFaceNo() != nextDms->GetFaceNo()) {
if (face == nl->TheEmptyList()) {
face = nl->OneElemList(cycle);
faceLastElem = face;
} else {
faceLastElem = nl->Append(faceLastElem, cycle);
}
if (i == num - 1 || dms->GetFaceNo() != nextDms->GetFaceNo()) {
if (faces == nl->TheEmptyList()) {
faces = nl->OneElemList(face);
facesLastElem = faces;
} else
facesLastElem = nl->Append(facesLastElem, face);
face = nl->TheEmptyList();
faceLastElem = face;
}
cycle = nl->TheEmptyList();
cycleLastElem = cycle;
}
}
ListExpr res = nl->TwoElemList(nl->FourElemList(OutDateTime(
nl->TheEmptyList(), SetWord((void*) &interval.start)), OutDateTime(
nl->TheEmptyList(), SetWord((void*) &interval.end)),
nl->BoolAtom(interval.lc), nl->BoolAtom(interval.rc)), faces);
return res;
}
URegionEmb*
ResultUnit::ConvertToURegionEmb(DbArray<MSegmentData>* segments) const {
#ifdef PRINT_STATISTIC
StopWatch stopWatch;
stopWatch.start();
#endif
const unsigned int segmentsStartPos = segments->Size();
URegionEmb* uregion = new URegionEmb(interval, segmentsStartPos);
double minX = MAX_DOUBLE;
double maxX = MIN_DOUBLE;
double minY = MAX_DOUBLE;
double maxY = MIN_DOUBLE;
for (unsigned int i = 0; i < msegments.size(); i++) {
const MSegment* mSeg = &msegments[i];
MSegmentData msd(mSeg->GetFaceNo(),
mSeg->GetCycleNo(),
mSeg->GetSegmentNo(),
mSeg->GetInsideAbove(),
mSeg->GetInitial().GetStart().GetX(),
mSeg->GetInitial().GetStart().GetY(),
mSeg->GetInitial().GetEnd().GetX(),
mSeg->GetInitial().GetEnd().GetY(),
mSeg->GetFinal().GetStart().GetX(),
mSeg->GetFinal().GetStart().GetY(),
mSeg->GetFinal().GetEnd().GetX(),
mSeg->GetFinal().GetEnd().GetY());
//msd.SetDegeneratedInitial(DGM_NONE);
//msd.SetDegeneratedFinal(DGM_NONE);
//uregion->PutSegment(segments, i, msd, true);
AddMSegmentData(uregion, segments, msd);
// Update the min/max values:
minX = min(minX, msd.GetInitialStartX());
minX = min(minX, msd.GetInitialEndX());
minX = min(minX, msd.GetFinalStartX());
minX = min(minX, msd.GetFinalEndX());
minY = min(minY, msd.GetInitialStartY());
minY = min(minY, msd.GetInitialEndY());
minY = min(minY, msd.GetFinalStartY());
minY = min(minY, msd.GetFinalEndY());
maxX = max(maxX, msd.GetInitialStartX());
maxX = max(maxX, msd.GetInitialEndX());
maxX = max(maxX, msd.GetFinalStartX());
maxX = max(maxX, msd.GetFinalEndX());
maxY = max(maxY, msd.GetInitialStartY());
maxY = max(maxY, msd.GetInitialEndY());
maxY = max(maxY, msd.GetFinalStartY());
maxY = max(maxY, msd.GetFinalEndY());
}
// Set the bbox:
double min[3] = { minX, minY, interval.start.ToDouble() };
double max[3] = { maxX, maxY, interval.end.ToDouble() };
uregion->SetBBox(Rectangle<3>(true, min, max));
/*
We have to go through the lists of degenerated segments and count
how often
a region is inside above in each list. If there are more inside above
segments than others, we need one inside above segment for the
~TemporalFunction()~ and set all others to ignore. Vice version if
there are more inside below segments. If there is the same number of
inside above and inside below segments, we can ignore the entire list.
*/
//bool nonTrivialInitial = false;
//bool nonTrivialFinal = false;
for (int i = 0; i < uregion->GetSegmentsNum(); i++) {
MSegmentData auxDms;
uregion->GetSegment(segments, i, auxDms);
MSegmentData dms( auxDms);
//if (!dms.GetPointInitial() && dms.GetDegeneratedInitialNext() < 0)
// nonTrivialInitial = true;
//if (!dms.GetPointFinal() && dms.GetDegeneratedFinalNext() < 0)
// nonTrivialFinal = true;
if (dms.GetDegeneratedInitial() == DGM_UNKNOWN) {
if (dms.GetDegeneratedInitialNext() >= 0) {
MSegmentData auxDegenDms;
MSegmentData degenDms;
unsigned int numInsideAbove = 0;
unsigned int numNotInsideAbove = 0;
for (int j = i+1; j != 0; j
= degenDms.GetDegeneratedInitialNext()) {
uregion->GetSegment(segments, j-1, auxDegenDms);
degenDms = auxDegenDms;
if (degenDms.GetInsideAbove())
numInsideAbove++;
else
numNotInsideAbove++;
if (j != i+1) {
degenDms.SetDegeneratedInitial(DGM_IGNORE);
uregion->PutSegment(segments, j-1, degenDms);
}
}
if (numInsideAbove == numNotInsideAbove) {
dms.SetDegeneratedInitial(DGM_IGNORE);
} else if (numInsideAbove == numNotInsideAbove+1) {
dms.SetDegeneratedInitial(DGM_INSIDEABOVE);
} else if (numInsideAbove+1 == numNotInsideAbove) {
dms.SetDegeneratedInitial(DGM_NOTINSIDEABOVE);
} else {
cerr << "segment (" << dms.GetInitialStartX() << ", "
<< dms.GetInitialStartY() << ")-("
<< dms.GetInitialEndX() << ", "
<< dms.GetInitialEndY() << ") / ("
<< dms.GetFinalStartX() << ", "
<< dms.GetFinalStartY() << ")-("
<< dms.GetFinalEndX() << ", "
<< dms.GetFinalEndY()
<< ") incorrectly degenerated "
<< "in initial instant" << endl;
delete uregion;
return 0;
}
} else
dms.SetDegeneratedInitial(DGM_NONE);
}
if (dms.GetDegeneratedFinal() == DGM_UNKNOWN) {
if (dms.GetDegeneratedFinalNext() >= 0) {
MSegmentData auxDegenDms;
MSegmentData degenDms;
unsigned int numInsideAbove = 0;
unsigned int numNotInsideAbove = 0;
for (int j = i+1; j != 0; j
= degenDms.GetDegeneratedFinalNext()) {
//cout << segments->Size()-1 << " " << j-1 << endl;
uregion->GetSegment(segments, j-1, auxDegenDms);
degenDms = auxDegenDms;
if (degenDms.GetInsideAbove())
numInsideAbove++;
else
numNotInsideAbove++;
if (j != i+1) {
degenDms.SetDegeneratedFinal(DGM_IGNORE);
uregion->PutSegment(segments, j-1, degenDms);
}
}
if (numInsideAbove == numNotInsideAbove) {
dms.SetDegeneratedFinal(DGM_IGNORE);
} else if (numInsideAbove == numNotInsideAbove+1) {
dms.SetDegeneratedFinal(DGM_INSIDEABOVE);
} else if (numInsideAbove+1 == numNotInsideAbove) {
dms.SetDegeneratedFinal(DGM_NOTINSIDEABOVE);
} else {
cerr << "segment (" << dms.GetInitialStartX() << ", "
<< dms.GetInitialStartY() << ")-("
<< dms.GetInitialEndX() << ", "
<< dms.GetInitialEndY() << ") / ("
<< dms.GetFinalStartX() << ", "
<< dms.GetFinalStartY() << ")-("
<< dms.GetFinalEndX() << ", "
<< dms.GetFinalEndY()
<< ") incorrectly degenerated "
<< "in final instant" << endl;
delete uregion;
return 0;
}
} else
dms.SetDegeneratedFinal(DGM_NONE);
}
uregion->PutSegment(segments, i, dms);
}
#ifdef PRINT_STATISTIC
statistic.durationConvertResultUnitToURegionEmb
+= stopWatch.diffSecondsReal();
#endif
//assert(Check());
return uregion;
}
void ResultUnit::Print(const bool segments) const {
cout << "unit: " << interval << endl << endl;
if (segments)
for (unsigned int i = 0; i < msegments.size(); i++) {
msegments[i].Print();
}
}
string ResultUnit::GetVRMLDesc() const {
std::ostringstream oss;
oss << endl;
oss << "# Interval: " << interval << endl;
oss << "# Interval: " << interval.start.ToDouble();
oss << " -> " << interval.end.ToDouble() << endl;
oss << endl;
oss << endl;
oss << "# Unit :" << endl;
oss << endl;
const double scale = VRML_SCALE_FACTOR;
oss << "Transform {" << endl;
oss << "\tscale " << scale << " " << scale << " " << scale << endl;
oss << "\tchildren [" << endl;
oss << "\t\tShape {" << endl;
oss << "\t\t\tgeometry IndexedLineSet {" << endl;
oss << "\t\t\t\tcoord Coordinate {" << endl;
oss << "\t\t\t\t\tpoint [" << endl;
int count = 0;
vector<MSegment>::const_iterator iter;
for (iter = msegments.begin(); iter != msegments.end(); iter++) {
const MSegment ms = *iter;
const Point3D a(ms.GetInitial().GetStart().GetX(),
ms.GetInitial().GetStart().GetY(),
interval.start.ToDouble());
const Point3D b(ms.GetInitial().GetEnd().GetX(),
ms.GetInitial().GetEnd().GetY(),
interval.start.ToDouble());
const Point3D c(ms.GetFinal().GetStart().GetX(),
ms.GetFinal().GetStart().GetY(),
interval.end.ToDouble());
const Point3D d(ms.GetFinal().GetEnd().GetX(),
ms.GetFinal().GetEnd().GetY(),
interval.end.ToDouble());
oss << "\t\t\t\t\t\t" << a.GetVRMLDesc()
<< c.GetVRMLDesc()
<< d.GetVRMLDesc()
<< b.GetVRMLDesc()
<< endl;
count++;
}
oss << "\t\t\t\t\t] # end point" << endl;
oss << "\t\t\t\t} # end coord" << endl;
oss << "\t\t\t\tcoordIndex [" << endl;
const int noPoints = count * 4;
for (int i = 0; i < noPoints; i += 4) {
oss << "\t\t\t\t\t" << i << ", " << i + 1 << ", " << i + 2
<< ", " << i + 3 << ", " << i << ", " << "-1," << endl;
}
oss << "\t\t\t\t] # end coordIndex" << endl;
//oss << "\t\t\t\tcolor Color { color [ " << color << " ] }" << endl;
oss << "\t\t\t} # end geometry" << endl;
oss << "\t\t} # end shape" << endl;
oss << "\t] # end children" << endl;
oss << "} # end Transform" << endl;
return oss.str();
}
void ResultUnit::AddMSegmentData(URegionEmb* uregion,
DbArray<MSegmentData>* segments,
MSegmentData& dms) const {
/*
For each of the already existing segments:
*/
const int segmentsNum = uregion->GetSegmentsNum();
const int segmentsStartPos = uregion->GetStartPos();
for (int i = segmentsNum - 1; i >= 0; i--) {
MSegmentData auxExistingDms;
segments->Get(segmentsStartPos + i, auxExistingDms);
MSegmentData existingDms( auxExistingDms );
/*
Check whether the current segment degenerates with this segment in the
initial instant. Note that segments reduced to points are excluded from
this.
All segments, which degenerate into each other, are collected in a list
using the ~degeneratedInitialNext~ attribute.
*/
if (dms.GetDegeneratedInitialNext() < 0
&& !dms.GetPointInitial()
&& !existingDms.GetPointInitial()
&& ((NumericUtil::NearlyEqual(
dms.GetInitialStartX(),
existingDms.GetInitialStartX())
&& NumericUtil::NearlyEqual(
dms.GetInitialStartY(),
existingDms.GetInitialStartY())
&& NumericUtil::NearlyEqual(
dms.GetInitialEndX(),
existingDms.GetInitialEndX())
&& NumericUtil::NearlyEqual(
dms.GetInitialEndY(),
existingDms.GetInitialEndY()))
|| (NumericUtil::NearlyEqual(
dms.GetInitialStartX(),
existingDms.GetInitialEndX())
&& NumericUtil::NearlyEqual(
dms.GetInitialStartY(),
existingDms.GetInitialEndY())
&& NumericUtil::NearlyEqual(
dms.GetInitialEndX(),
existingDms.GetInitialStartX())
&& NumericUtil::NearlyEqual(
dms.GetInitialEndY(),
existingDms.GetInitialStartY())))) {
dms.SetDegeneratedInitialNext(0);
existingDms.SetDegeneratedInitialNext(segmentsNum + 1);
segments->Put(segmentsStartPos + i, existingDms);
}
/*
Same for the final instant.
*/
if (dms.GetDegeneratedFinalNext() < 0
&& !dms.GetPointFinal()
&& !existingDms.GetPointFinal()
&& ((NumericUtil::NearlyEqual(
dms.GetFinalStartX(),
existingDms.GetFinalStartX())
&& NumericUtil::NearlyEqual(
dms.GetFinalStartY(),
existingDms.GetFinalStartY())
&& NumericUtil::NearlyEqual(
dms.GetFinalEndX(),
existingDms.GetFinalEndX())
&& NumericUtil::NearlyEqual(
dms.GetFinalEndY(),
existingDms.GetFinalEndY()))
|| (NumericUtil::NearlyEqual(
dms.GetFinalStartX(),
existingDms.GetFinalEndX())
&& NumericUtil::NearlyEqual(
dms.GetFinalStartY(),
existingDms.GetFinalEndY())
&& NumericUtil::NearlyEqual(
dms.GetFinalEndX(),
existingDms.GetFinalStartX())
&& NumericUtil::NearlyEqual(
dms.GetFinalEndY(),
existingDms.GetFinalStartY())))) {
dms.SetDegeneratedFinalNext(0);
existingDms.SetDegeneratedFinalNext(segmentsNum + 1);
segments->Put(segmentsStartPos + i, existingDms);
}
}
segments->resize(segmentsStartPos + segmentsNum + 1);
segments->Put(segmentsStartPos + segmentsNum, dms);
uregion->SetSegmentsNum(segmentsNum + 1);
}
bool ResultUnit::Check() const {
for (unsigned int i = 0; i < msegments.size() - 1; i++) {
const MSegment* ms1 = &msegments[i];
const MSegment* ms2 = &msegments[i+1];
const Point2D a1(ms1->GetInitial().GetStart());
const Point2D c1(ms1->GetFinal().GetStart());
const Point2D a2(ms2->GetInitial().GetStart());
const Point2D c2(ms2->GetFinal().GetStart());
if (a1 == a2 && c1 == c2) {
flippedPFaces.insert(msegments[i-1].GetPFace()->GetID());
flippedPFaces.insert(ms1->GetPFace()->GetID());
}
}
return flippedPFaces.empty();
}
/*
1 Class Point3DExt
*/
bool Point3DExt::operator <(const Point3DExt& p) const {
if (NumericUtil::Lower(GetX(), p.GetX()))
return true;
if (NumericUtil::Greater(GetX(), p.GetX()))
return false;
if (NumericUtil::Lower(GetY(), p.GetY()))
return true;
if (NumericUtil::Greater(GetY(), p.GetY()))
return false;
if (NumericUtil::Lower(GetT(), p.GetT()))
return true;
if (NumericUtil::Greater(GetT(), p.GetT()))
return false;
//cout << "sourceFlag < p.sourceFlag" << endl;
return sourceFlag < p.sourceFlag;
}
bool PointExtSet::GetIntersectionSegment(Segment3D& result) const {
if (s.size() != 4)
return false;
set<Point3DExt>::iterator it = s.begin();
Point3DExt p1 = *it;
it++;
Point3DExt p2 = *it;
if (p1.sourceFlag == p2.sourceFlag)
return false;
it++;
Point3DExt p3 = *it;
if (p2 == p3) {
// The length of the intersection segment is zero.
return false;
}
result = Segment3D(p2, p3);
return true;
}
void PointExtSet::Print() const {
set<Point3DExt>::iterator iter;
for (iter = s.begin(); iter != s.end(); ++iter) {
cout << *iter << endl;
}
}
/*
1 Struct IntSegCompare
*/
bool IntSegCompare::operator()(const IntersectionSegment* const& s1,
const IntersectionSegment* const& s2) const {
// We sort by (t_start, w_start, IsLeft())
// Precondition: s1->GetStartT() < s1->GetEndT() &&
// s2->GetStartT() < s2->GetEndT()
if (NumericUtil::Lower(s1->GetStartT(), s2->GetStartT()))
return true;
if (NumericUtil::Greater(s1->GetStartT(), s2->GetStartT()))
return false;
// s1->GetStartT() == s2->GetStartT()
if (NumericUtil::Lower(s1->GetStartW(), s2->GetStartW()))
return true;
if (NumericUtil::Greater(s1->GetStartW(), s2->GetStartW()))
return false;
// s1->GetStartW() == s2->GetStartW()
if (*(s1->GetEndWT()) == *(s2->GetEndWT()))
return true;
//return s1->IsLeftOf(s2);
return s1->GetEndWT()->IsLeft(*(s2->GetStartWT()), *(s2->GetEndWT()));
}
/*
1 Class IntSegContainer
*/
IntSegContainer::~IntSegContainer() {
set<IntersectionSegment*>::iterator iter;
for (iter = intSegs.begin(); iter != intSegs.end(); ++iter) {
delete *iter;
}
}
void IntSegContainer::UpdateTimeLevel(double _t) {
if (firstTimeLevel) {
intSegIter = intSegs.begin();
firstTimeLevel = false;
}
t = _t;
activeIter = active.begin();
while (activeIter != active.end()) {
while (activeIter != active.end() && IsOutOfRange(*activeIter)) {
activeIter = active.erase(activeIter);
}
if (activeIter == active.end())
break;
if (HasMoreSegsToInsert()) {
IntersectionSegment* newSeg = *intSegIter;
if (newSeg->IsLeftOf(*activeIter)) {
activeIter = active.insert(activeIter, newSeg);
intSegIter++;
}
}
activeIter++;
}
assert(activeIter == active.end());
// Add the tail, if there is one:
while (HasMoreSegsToInsert()) {
IntersectionSegment* newSeg = *intSegIter;
activeIter = active.insert(activeIter, newSeg);
intSegIter++;
activeIter = active.end();
}
}
void IntSegContainer::Print() const {
if (intSegs.empty()) {
cout << "Empty." << endl;
return;
}
set<IntersectionSegment*>::const_iterator iter;
for (iter = intSegs.begin(); iter != intSegs.end(); ++iter) {
//cout << (*iter)->GetID() << " ";
(*iter)->Print();
cout << endl;
}
}
void IntSegContainer::PrintActive() const {
list<IntersectionSegment*>::const_iterator iter;
for (iter = active.begin(); iter != active.end(); ++iter) {
cout << (*iter)->GetID() << " ";
//(*iter)->Print();
}
}
/*
1 Class PFace
*/
unsigned int PFace::instanceCount = 0;
PFace::PFace(SourceUnit* _unit, const MSegmentData* _mSeg) :
unit(_unit),
mSeg(_mSeg),
//insideAbove(_mSeg->GetInsideAbove()),
hasInnerIntSegs(false),
state(UNKNOWN),
id(instanceCount++) {
SetInitialStartPointIsA();
ComputeBoundingRect();
ComputeNormalVector();
ComputeWTCoords();
}
void PFace::SetInitialStartPointIsA() {
Point2D start;
Point2D end;
if (!mSeg->GetPointInitial()) {
start = Point2D(mSeg->GetInitialStartX(), mSeg->GetInitialStartY());
end = Point2D(mSeg->GetInitialEndX(), mSeg->GetInitialEndY());
} else {
start = Point2D(mSeg->GetFinalStartX(), mSeg->GetFinalStartY());
end = Point2D(mSeg->GetFinalEndX(), mSeg->GetFinalEndY());
}
initialStartPointIsA = (start < end) == mSeg->GetInsideAbove();
}
bool PFace::IntersectionPlaneSegment(const Segment3D& seg, Point3D& result) {
// Precondition:
// We compute the intersection point
// of the plane - defined by the PFace - and the segment.
Vector3D u = seg.GetEnd() - seg.GetStart();
Vector3D w = seg.GetStart() - this->GetA_XYT();
double d = this->GetNormalVector() * u;
double n = -this->GetNormalVector() * w;
if (NumericUtil::NearlyEqual(d, 0.0)) // Segment is parallel to plane.
return false;
double s = n / d;
// No intersection point, if s < -eps or s > 1 + eps.
if (NumericUtil::Lower(s, 0.0) || NumericUtil::Greater(s, 1.0))
//const double eps = 0.0001;
//if (s < -eps || s > 1 + eps)
return false;
// Compute segment intersection point:
result = seg.GetStart() + s * u;
return true;
}
void PFace::Intersection(PFace& other) {
assert(IsPartOfUnitA());
#ifdef OPTIMIZE_BY_BOUNDING_RECT
if (!GetBoundingRect().Intersects(other.GetBoundingRect()))
return;
#endif
if (this->IsParallelTo(other)) {
if (this->IsCoplanarTo(other)) {
this->MarkAsCriticalRelevant();
other.MarkAsCriticalRelevant();
//cout << "Coplanar PFace pair found." << endl;
} else {
//cout << "Parallel PFace pair found." << endl;
}
return;
}
// We store all edges of this PFace as 3DSegments in the vector edgesPFaceA:
vector<Segment3D> edgesPFaceA;
edgesPFaceA.push_back(Segment3D(this->GetA_XYT(), this->GetC_XYT()));
edgesPFaceA.push_back(Segment3D(this->GetB_XYT(), this->GetD_XYT()));
if (!this->GetMSeg()->GetPointInitial())
edgesPFaceA.push_back(Segment3D(this->GetA_XYT(), this->GetB_XYT()));
if (!this->GetMSeg()->GetPointFinal())
edgesPFaceA.push_back(Segment3D(this->GetC_XYT(), this->GetD_XYT()));
// We store all edges of the other PFace as 3DSegments
// in the vector edgesPFaceB:
vector<Segment3D> edgesPFaceB;
edgesPFaceB.push_back(Segment3D(other.GetA_XYT(), other.GetC_XYT()));
edgesPFaceB.push_back(Segment3D(other.GetB_XYT(), other.GetD_XYT()));
if (!other.GetMSeg()->GetPointInitial())
edgesPFaceB.push_back(Segment3D(other.GetA_XYT(), other.GetB_XYT()));
if (!other.GetMSeg()->GetPointFinal())
edgesPFaceB.push_back(Segment3D(other.GetC_XYT(), other.GetD_XYT()));
PointExtSet intPointSet;
Point3DExt intPoint;
// Intersect the plane - defined by the other PFace -
// with all edges of this PFace:
unsigned int i = 0;
while (intPointSet.Size() < 2 && i < edgesPFaceA.size()) {
if (other.IntersectionPlaneSegment(edgesPFaceA[i], intPoint)) {
intPoint.sourceFlag = PFACE_A;
intPointSet.Insert(intPoint);
}
i++;
}
if (intPointSet.Size() != 2) // We need exactly two intersection points.
return;
// Intersect the plane - defined by this PFace -
// with all edges of the other PFace:
unsigned int j = 0;
while (intPointSet.Size() < 4 && j < edgesPFaceB.size()) {
if (this->IntersectionPlaneSegment(edgesPFaceB[j], intPoint)) {
intPoint.sourceFlag = PFACE_B;
intPointSet.Insert(intPoint);
}
j++;
}
Segment3D intSeg;
if (!intPointSet.GetIntersectionSegment(intSeg))
return; // There is no intersection.
#ifdef PRINT_DEBUG_MESSAGES
if (intSeg.Length() < 0.1) {
cout << "intSeg.Length(): " << intSeg.Length() << endl;
cout << "intSeg: " << intSeg << endl;
cout << "intPointSet: " << endl;
intPointSet.Print();
}
#endif
// We add one intersection segment to each PFace:
this->AddIntSeg(intSeg, other);
other.AddIntSeg(intSeg, *this);
//statistic.noIntSegsTotal += 2;
}
void PFace::ComputeBoundingRect() {
pair<double, double> x = NumericUtil::MinMax4(mSeg->GetInitialStartX(),
mSeg->GetInitialEndX(),
mSeg->GetFinalStartX(),
mSeg->GetFinalEndX());
pair<double, double> y = NumericUtil::MinMax4(mSeg->GetInitialStartY(),
mSeg->GetInitialEndY(),
mSeg->GetFinalStartY(),
mSeg->GetFinalEndY());
double minMax[] = {x.first - NumericUtil::eps,
x.second + NumericUtil::eps,
y.first - NumericUtil::eps,
y.second + NumericUtil::eps};
boundingRect = Rectangle<2>(true,minMax );
}
void PFace::ComputeWTCoords() {
// The vector w is either the normalized cross product
// of the normal vector and the t-unit-vector, or it's opposite.
// This depends on the kind of set-operation, we want to perform.
// wVector = Vector3D(GetNormalVector() ^ Vector3D(0.0, 0.0, 1.0);
// wVector.Normalize();
// This can be simplified to:
wVector = Vector3D(GetNormalVector().GetY(),
- GetNormalVector().GetX(),
0.0);
// Usually, we look at the PFace from the inside.
if (GetOperation() == MINUS && IsPartOfUnitB()) {
// Only in this case, we want to look from the outside.
wVector = - wVector;
}
wVector.Normalize();
// For the sake of efficency, we cache the w-coords of some points:
aW = TransformToW(this->GetA_XYT());
bW = TransformToW(this->GetB_XYT());
cW = TransformToW(this->GetC_XYT());
dW = TransformToW(this->GetD_XYT());
}
void PFace::ComputeNormalVector() {
if (!AEqualsB()) {
// Cross product of vector AB and AC:
normalVector = (GetB_XYT() - GetA_XYT()) ^ (GetC_XYT() - GetA_XYT());
} else { // A == B
// Cross product of vector DC and DB:
normalVector = (GetC_XYT() - GetD_XYT()) ^ (GetB_XYT() - GetD_XYT());
}
normalVector.Normalize();
}
void PFace::DecideRelevanceAndAddBoundary() {
if (!DECIDE_BY_ENTIRELY_IN_OUT) {
if (GetState() == UNKNOWN || IsIrrelevant())
MarkAsNormalRelevant();
}
if (IsIrrelevant()) {
return;
}
if (IsNormalRelevant() || IsCriticalRelevant()) {
AddEntireBoundary();
return;
}
// The PFace has no intersection segments and it's unknown, if
// it is relevant for the result.
// Check, if the PFace is outside or inside
// of the other region unit
// and add intSegs depending of the operation.
const SetOp op = unit->GetOperation();
if (unit->GetPartner()->IsEntirelyOutside(this)) {
//MarkAsEntirelyOutside();
if (op == UNION || (op == MINUS && IsPartOfUnitA())) {
AddEntireBoundary();
} else {
// op == INTERSECTION || (op == MINUS && IsPartOfUnitB()):
MarkAsIrrelevant();
}
} else { // The PFace is entirely inside of the other unit.
//MarkAsEntirelyInside();
if (op == INTERSECTION || (op == MINUS && IsPartOfUnitB())) {
AddEntireBoundary();
} else {
// op == UNION || (op == MINUS && IsPartOfUnitA()):
MarkAsIrrelevant();
}
}
}
void PFace::AddEntireBoundary() {
AddBoundaryIntSeg(Segment3D(GetA_XYT(), GetC_XYT()));
AddBoundaryIntSeg(Segment3D(GetB_XYT(), GetD_XYT()));
}
bool PFace::IsParallelTo(const PFace& pf) const {
Vector3D cross = GetNormalVector() ^ pf.GetNormalVector();
//cross.Normalize();
return cross.IsZero();
}
bool PFace::IsCoplanarTo(const PFace& pf) const {
// Precondition: this is parallel to pf.
return IsCoplanarTo(pf.GetA_XYT());
}
bool PFace::IsCoplanarTo(const Point3D& p) const {
const double distance2 = p.DistanceToPlane2(GetA_XYT(), GetNormalVector());
return NumericUtil::NearlyEqual(distance2, 0.0);
}
bool PFace::IsCoplanarTo(const Segment3D& seg) const {
return IsCoplanarTo(seg.GetStart()) && IsCoplanarTo(seg.GetEnd());
}
bool PFace::IsCoplanarTo(const IntersectionSegment& seg) const {
return IsCoplanarTo(Segment3D(*seg.GetStartXYT(), *seg.GetEndXYT()));
}
bool PFace::HasEqualNormalVector(const PFace& pf) const {
// Precondition: this is parallel to pf.
// The normal vectors are equal, iff
// the cosinus of the angle between them is positive:
return GetNormalVector() * pf.GetNormalVector() > 0.0;
}
bool PFace::IsColinearToBoundary(const Segment3D& s) const {
return GetRelationToBoundary(s, LEFT_BOUNDARY) == COLINEAR ||
GetRelationToBoundary(s, RIGHT_BOUNDARY) == COLINEAR;
}
const RelationToBoundary
PFace::GetRelationToBoundary(const Segment3D& s, const Boundary b) const {
const Segment2D sWT = TransformToWT(s);
const Segment2D boundary = GetBoundary(b);
const bool startOnBoundary = sWT.GetStart().IsColinear(boundary);
const bool endOnBoundary = sWT.GetEnd().IsColinear(boundary);
if (!startOnBoundary && !endOnBoundary) {
return NO_TOUCH;
}
if (startOnBoundary && endOnBoundary) {
return COLINEAR;
}
if (startOnBoundary) {
return TOUCH_IN_STARTPOINT;
}
// if (endOnBoundary) {
return TOUCH_IN_ENDPOINT;
//}
}
const Point3D PFace::GetMidPoint() const {
const Point3D a((GetA_XYT() + GetC_XYT()) * 0.5);
const Point3D b((GetB_XYT() + GetD_XYT()) * 0.5);
return Point3D((a + b) * 0.5);
}
void PFace::AddIntSeg(const Segment3D& seg, PFace& other) {
const RelationToBoundary rtlb = GetRelationToBoundary(seg, LEFT_BOUNDARY);
switch (rtlb) {
case NO_TOUCH:
MarkAsNormalRelevant();
break;
case TOUCH_IN_STARTPOINT:
MarkAsNormalRelevant();
intSegs.AddCriticalTime(seg.GetStart().GetT());
break;
case TOUCH_IN_ENDPOINT:
MarkAsNormalRelevant();
intSegs.AddCriticalTime(seg.GetEnd().GetT());
break;
case COLINEAR:
MarkAsCriticalRelevant();
other.MarkAsCriticalRelevant();
break;
}
unit->AddGlobalTimeValue(seg.GetStart().GetT());
unit->AddGlobalTimeValue(seg.GetEnd().GetT());
hasInnerIntSegs = true;
if (!seg.IsOrthogonalToTAxis()) {
//assert(this->IsCoplanarTo(seg));
IntersectionSegment* intSeg = new IntersectionSegment(seg);
//assert(this->IsCoplanarTo(*intSeg));
intSeg->SetPFace(this);
intSeg->SetWCoords();
//intSeg->SetSideOfResultFace(*this, other);
intSegs.AddIntSeg(intSeg);
}
}
void PFace::AddBoundaryIntSeg(const Segment3D& seg) {
MarkAsNormalRelevant();
unit->AddGlobalTimeValue(seg.GetStart().GetT());
unit->AddGlobalTimeValue(seg.GetEnd().GetT());
IntersectionSegment* intSeg = new IntersectionSegment(seg);
intSeg->SetPFace(this);
intSeg->SetWCoords();
intSegs.AddIntSeg(intSeg);
statistic.noBorderIntSegs++;
}
string PFace::GetVRMLDesc() {
return GetA_XYT().GetVRMLDesc() +
GetC_XYT().GetVRMLDesc() +
GetD_XYT().GetVRMLDesc() +
GetB_XYT().GetVRMLDesc();
}
string PFace::GetStateAsString() const {
const State state = GetState();
switch (state) {
case UNKNOWN:
return "UNKNOWN";
case ENTIRELY_INSIDE:
return "ENTIRELY_INSIDE";
case ENTIRELY_OUTSIDE:
return "ENTIRELY_OUTSIDE";
case RELEVANT_NOT_CRITICAL:
return "RELEVANT_NOT_CRITICAL";
case RELEVANT_CRITICAL:
return "RELEVANT_CRITICAL";
case NOT_RELEVANT:
return "NOT_RELEVANT";
}
// Should never be reached:
return "I don't know this state!";
}
void PFace::Print() const {
cout << "PFace ID: " << GetID() << endl;
cout << endl;
//cout << "Starttime: " << unit->GetStartTime() << endl;
//cout << "Endtime: " << unit->GetEndTime() << endl;
cout << "A_XYT: " << GetA_XYT() << endl;
cout << "B_XYT: " << GetB_XYT() << endl;
cout << "C_XYT: " << GetC_XYT() << endl;
cout << "D_XYT: " << GetD_XYT() << endl;
cout << endl;
cout << "A_WT: " << GetA_WT() << endl;
cout << "B_WT: " << GetB_WT() << endl;
cout << "C_WT: " << GetC_WT() << endl;
cout << "D_WT: " << GetD_WT() << endl;
cout << endl;
cout << "Normal vector: " << GetNormalVector() << endl;
cout << "W vector: " << GetWVector() << endl;
cout << endl;
cout << "State: " << GetStateAsString() << endl;
//cout << "mSeg->GetInsideAbove(): " << mSeg->GetInsideAbove() << endl;
cout << endl;
cout << "IntersectionSegments: "<< endl;
intSegs.Print();
cout << endl;
cout << endl;
cout << "*********************************************" << endl;
cout << endl;
}
} // end of namespace mregionops
} // end of namespace temporalalgebra