280 lines
11 KiB
C++
280 lines
11 KiB
C++
|
|
/*
|
||
|
|
1 interpolate.cpp is the home of the main interpolation recursion.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "interpolate.h"
|
||
|
|
|
||
|
|
#include <string>
|
||
|
|
|
||
|
|
|
||
|
|
void handleIntersections(MFaces& children, MFace parent, bool evap);
|
||
|
|
vector<MFace> MergeFaces (Matches& m);
|
||
|
|
|
||
|
|
// This variable holds the pointer to the matching strategy to use
|
||
|
|
vector<Matches> (*matchingStrategy)(vector<Face>*,vector<Face>*,
|
||
|
|
int,string);
|
||
|
|
|
||
|
|
/*
|
||
|
|
1.1 ~Interpolate~
|
||
|
|
|
||
|
|
Main interpolation function between two lists of regions.
|
||
|
|
It calls the matching-function to create pairs of regions from the source- and
|
||
|
|
destination-list and interpolates the convex hulls of these regions using the
|
||
|
|
RotatingPlane algorithm. It then creates two new lists from the concavities and
|
||
|
|
holes of the region and recurses. The result of the recursion is then merged
|
||
|
|
into the current result. Intersections are detected and tried to be compensated
|
||
|
|
|
||
|
|
*/
|
||
|
|
MFaces interpolate(vector<Face> *sregs, vector<Face> *dregs, int depth,
|
||
|
|
bool evap, string args) {
|
||
|
|
MFaces ret;
|
||
|
|
|
||
|
|
DEBUG(1, "== Entering Interpolate depth " << depth << " ==");
|
||
|
|
|
||
|
|
if (sregs->empty() && dregs->empty()) // Nothing to do!
|
||
|
|
return ret;
|
||
|
|
|
||
|
|
// Remember the original faces-lists from which the result was created.
|
||
|
|
ret.sregs = sregs;
|
||
|
|
ret.dregs = dregs;
|
||
|
|
|
||
|
|
// Match the faces to pairs of faces in the source- and destination-realm
|
||
|
|
// If we are in the evaporation (or condensation) phase, just try to match
|
||
|
|
// equal faces by their lower left point.
|
||
|
|
vector<Matches> matches;
|
||
|
|
if (!evap)
|
||
|
|
matches = matchFaces(sregs, dregs, depth, args);
|
||
|
|
else
|
||
|
|
matches = matchFaces(sregs, dregs, depth, "lowerleft");
|
||
|
|
|
||
|
|
|
||
|
|
for (unsigned int i = 0; i < matches.size(); i++) {
|
||
|
|
Matches p = matches[i];
|
||
|
|
|
||
|
|
Face *src;
|
||
|
|
Face *dst;
|
||
|
|
|
||
|
|
// This is only a temporary hack to demonstrate face merging.
|
||
|
|
int merged = 0;
|
||
|
|
if (p.src.size() > 1 || p.dst.size() > 1) {
|
||
|
|
if (p.src.size() > 1)
|
||
|
|
merged = 1;
|
||
|
|
else
|
||
|
|
merged = 2;
|
||
|
|
vector<MFace> fcs = MergeFaces(p);
|
||
|
|
if (fcs.empty())
|
||
|
|
merged = 0;
|
||
|
|
for (unsigned int i = 0; i < fcs.size(); i++) {
|
||
|
|
fcs[i].half = merged;
|
||
|
|
ret.AddMFace(fcs[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
src = p.srcface();
|
||
|
|
dst = p.dstface();
|
||
|
|
|
||
|
|
if (src && dst) {
|
||
|
|
|
||
|
|
// Use the RotatingPlane-Algorithm to create an interpolation of
|
||
|
|
// the convex hull of src and dst and identify all concavities
|
||
|
|
RotatingPlane rp(src, dst, depth, evap);
|
||
|
|
|
||
|
|
// Recurse and try to match and interpolate the list of concavities
|
||
|
|
MFaces fcs = interpolate(&rp.scvs, &rp.dcvs, depth+1, evap, args);
|
||
|
|
if (merged) {
|
||
|
|
rp.mface.half = 3 - merged;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Now check if the interpolations intersect in any way
|
||
|
|
handleIntersections(fcs, rp.mface, evap);
|
||
|
|
|
||
|
|
// Inherit if the interpolation needs a evaporisation- or
|
||
|
|
// condensation-phase
|
||
|
|
ret.needSEvap = ret.needSEvap || fcs.needSEvap;
|
||
|
|
ret.needDEvap = ret.needDEvap || fcs.needDEvap;
|
||
|
|
|
||
|
|
// Try to merge the recursively created moving segments with the
|
||
|
|
// parent rp.mface
|
||
|
|
for (unsigned int i = 0; i < fcs.faces.size(); i++) {
|
||
|
|
// The holes of the faces are new faces now
|
||
|
|
// Since they should be completely contained by their parent,
|
||
|
|
// an intersection-check is unnecessary. Intersections with
|
||
|
|
// each other were already checked one recursion level lower.
|
||
|
|
for (unsigned int j = 0; j < fcs.faces[i].holes.size(); j++) {
|
||
|
|
MFace fc(fcs.faces[i].holes[j]);
|
||
|
|
ret.AddMFace(fc);
|
||
|
|
}
|
||
|
|
// Add the cycles to its parent
|
||
|
|
rp.mface.AddConcavity(fcs.faces[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// and try to merge them into the cycle here (otherwise they are
|
||
|
|
// added as a hole)
|
||
|
|
vector<MFace> splits = rp.mface.MergeConcavities();
|
||
|
|
// Now the resulting moving face is added to the return value
|
||
|
|
ret.AddMFace(rp.mface);
|
||
|
|
for (unsigned int i = 0; i < splits.size(); i++)
|
||
|
|
ret.AddMFace(splits[i]);
|
||
|
|
} else if (src || dst) {
|
||
|
|
// Our face doesn't have a partner, so the recursion stops here and
|
||
|
|
// we collapse (or expand) the face together with its holes
|
||
|
|
Face *r = src ? src : dst;
|
||
|
|
MFace coll = r->collapseWithHoles(r == src);
|
||
|
|
ret.AddMFace(coll);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Toplevel-Intersections are still not handled yet, do that now.
|
||
|
|
if (depth == 0) {
|
||
|
|
handleIntersections(ret, MFace(), evap);
|
||
|
|
}
|
||
|
|
|
||
|
|
DEBUG(1, "== Leaving Interpolate depth " << depth << " ==");
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
1.2 ~handleIntersections~ checks the newly created moving faces ~children~
|
||
|
|
for intersection with each other or their parent ~parent~.
|
||
|
|
|
||
|
|
If a real interpolation intersects, then we remove it and collapse/expand the
|
||
|
|
source- and destinationface of that moving face. If both intersecting moving
|
||
|
|
faces are already collapsed or expanded, then one of them is removed and we
|
||
|
|
need an evaporation- or condensationphase.
|
||
|
|
If we currently are in the evaporation- or condensationphase, then ~evap~ is
|
||
|
|
set and we handle intersections a little different.
|
||
|
|
|
||
|
|
*/
|
||
|
|
void handleIntersections(MFaces& children, MFace parent, bool evap) { return;
|
||
|
|
vector<MSegs> evp; // The list of evaporation-mfaces
|
||
|
|
|
||
|
|
// precalculate the bounding boxes of the children and the parent
|
||
|
|
for (int i = 0; i < (int) children.faces.size(); i++) {
|
||
|
|
children.faces[i].face.calculateBBox();
|
||
|
|
}
|
||
|
|
parent.face.calculateBBox();
|
||
|
|
|
||
|
|
// Now check all pairs of faces of children and the parent, but skip
|
||
|
|
// symmetric and reflexive pairs.
|
||
|
|
for (int i = 0; i < (int) children.faces.size(); i++) {
|
||
|
|
MFace *fs1 = &children.faces[i];
|
||
|
|
for (int j = 0; j <= i; j++) {
|
||
|
|
MFace *fs2 = (j == 0) ? &parent : &children.faces[j - 1];
|
||
|
|
if (fs1->half != fs2->half)
|
||
|
|
continue;
|
||
|
|
MSegs *s1 = &fs1->face;
|
||
|
|
MSegs *s2 = &fs2->face;
|
||
|
|
|
||
|
|
if (s1->intersects(*s2, false, false)) {
|
||
|
|
// We have found two intersecting moving faces.
|
||
|
|
pair<MSegs, MSegs> ss;
|
||
|
|
if (!s1->iscollapsed && !evap) {
|
||
|
|
// If this moving face is not collapsed and we do not
|
||
|
|
// evaporate then break the connection and collapse/expand
|
||
|
|
// the related faces.
|
||
|
|
ss = s1->kill(); // Create the pair of MSegs
|
||
|
|
// Remove the original object from the list
|
||
|
|
children.faces.erase(children.faces.begin()+i);
|
||
|
|
} else if (!s2->iscollapsed && (s2 != &parent.face)
|
||
|
|
&& !evap) {
|
||
|
|
// s1 already was collapsed but s2 is not, so this is the
|
||
|
|
// victim now. Refuse to remove the parent.
|
||
|
|
ss = s2->kill();
|
||
|
|
children.faces.erase(children.faces.begin() + (j-1));
|
||
|
|
} else {
|
||
|
|
// Both intersecting objects are already collapsing or
|
||
|
|
// expanding (or we are evaporating right now)
|
||
|
|
MSegs *rm;
|
||
|
|
if (evap) {
|
||
|
|
// Evaporation- or Condensation-Phase.
|
||
|
|
// Minimum one of the two definitively is already
|
||
|
|
// collapsing/expanding, choose this one
|
||
|
|
if (s1->iscollapsed && !s1->isevaporating)
|
||
|
|
rm = s1;
|
||
|
|
else if (!s2->isevaporating && (s2 != &parent.face))
|
||
|
|
rm = s2;
|
||
|
|
else // cannot be a real intersection, continue
|
||
|
|
continue;
|
||
|
|
vector<MSegs> ms;
|
||
|
|
// iscollapsed is 1, if the mface is collapsing,
|
||
|
|
// otherwise (2) it is expanding and we have to
|
||
|
|
// condensate it
|
||
|
|
if (rm->iscollapsed == 1) {
|
||
|
|
ms = rm->sreg.Evaporate(true);
|
||
|
|
} else {
|
||
|
|
ms = rm->dreg.Evaporate(false);
|
||
|
|
}
|
||
|
|
// Insert the evaporation-cycles into the list
|
||
|
|
children.faces.insert(children.faces.end(),
|
||
|
|
ms.begin(), ms.end());
|
||
|
|
evp.insert(evp.end(), ms.begin(), ms.end());
|
||
|
|
} else {
|
||
|
|
// We are in the main interpolation and cannot
|
||
|
|
// compensate this intersection. Remove one offending
|
||
|
|
// object and save, that we have to evaporate or
|
||
|
|
// condensate to fix that up.
|
||
|
|
rm = s1;
|
||
|
|
// iscollapsed is 1, if the mface is collapsing,
|
||
|
|
// otherwise (2) it is expanding and we have to
|
||
|
|
// do a condensation-phase
|
||
|
|
if (rm->iscollapsed == 1)
|
||
|
|
children.needSEvap = true;
|
||
|
|
else
|
||
|
|
children.needDEvap = true;
|
||
|
|
}
|
||
|
|
// Simply erase the offending object from the list now,
|
||
|
|
// either we have already created evaporisation/condensation
|
||
|
|
// cycles or we marked that we have to fix things up later
|
||
|
|
children.faces.erase(children.faces.begin()+
|
||
|
|
(rm == s1 ? i : j - 1));
|
||
|
|
// Restart the checks with the last face, since we changed
|
||
|
|
// the lists
|
||
|
|
i--;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
// Add the collapse- and expand-cycles
|
||
|
|
children.AddMFace(ss.first);
|
||
|
|
children.AddMFace(ss.second);
|
||
|
|
// Restart the checks one object earlier, since we removed
|
||
|
|
// the current object and the following objects filled the gap.
|
||
|
|
i-=2;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Insert the evaporation- and condensation-cycles into the list of faces
|
||
|
|
// children.faces.insert(children.faces.end(), evp.begin(), evp.end());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
1.3 ~regioninterpolate~ is the interface to the interpolation library.
|
||
|
|
|
||
|
|
Input:
|
||
|
|
src - Source region in nested list representation
|
||
|
|
dst - Destination region in nested list representation
|
||
|
|
start - Timestamp of source region in ms since 1970-01-01 00:00
|
||
|
|
end - Timestamp of destination region in ms since 1970-01-01 00:00
|
||
|
|
args - Parameterstring for the face matching strategy
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
The moving region in nested list representation
|
||
|
|
|
||
|
|
*/
|
||
|
|
RList regioninterpolate(RList src, RList dst,
|
||
|
|
string start, string end, string args) {
|
||
|
|
|
||
|
|
vector<Face> sregs = Face::getFaces(src);
|
||
|
|
vector<Face> dregs = Face::getFaces(dst);
|
||
|
|
|
||
|
|
// Create the interpolation from the lists of faces
|
||
|
|
MFaces mf = interpolate(&sregs, &dregs, 0, false, args);
|
||
|
|
|
||
|
|
Interval iv(start, end, true, true);
|
||
|
|
|
||
|
|
return mf.ToMListExpr(iv);
|
||
|
|
}
|
||
|
|
|