1311 lines
39 KiB
C++
1311 lines
39 KiB
C++
/*
|
|
* This file is part of libpmregion
|
|
*
|
|
* File: PMRegion\_conversions.cpp
|
|
* Author: Florian Heinz <fh@sysv.de>
|
|
|
|
1 Conversions
|
|
Conversions from PMRegion to other formats
|
|
like MRegion and OFF and vice versa
|
|
|
|
*/
|
|
|
|
|
|
#include "PMRegion_internal.h"
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <map>
|
|
#include <ctime>
|
|
|
|
using namespace std;
|
|
using namespace pmr;
|
|
|
|
namespace pmr {
|
|
|
|
/*
|
|
C O N V E R S I O N S
|
|
|
|
*/
|
|
|
|
|
|
/*
|
|
Conversion functions from and to OFF file format.
|
|
This is directly handled by CGAL
|
|
|
|
*/
|
|
|
|
ostream& operator<<(ostream& os, const Point_3& ms) {
|
|
os << ms._x << " " << ms._y << " " << ms._z;
|
|
return os;
|
|
}
|
|
|
|
|
|
PMRegion PMRegion::fromOFF(std::string off) {
|
|
PMRegion ret;
|
|
std::stringstream ss;
|
|
|
|
ss << off;
|
|
ss >> ret.polyhedron;
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::string PMRegion::toOFF() {
|
|
std::stringstream ss;
|
|
|
|
ss << setprecision(PRECISION) << polyhedron;
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
Conversion functions from and to mregions.
|
|
The mregion must be in RList format.
|
|
|
|
*/
|
|
|
|
// build_from_mregion builds a polyhedron from a list of surfaces
|
|
template <class HDS> class build_from_mregion:public CGAL::Modifier_base<HDS> {
|
|
public:
|
|
RList& mc;
|
|
Kernel::FT starttime, endtime;
|
|
|
|
build_from_mregion(RList& _reg, Kernel::FT _st, Kernel::FT _et) :
|
|
mc(_reg), starttime(_st), endtime(_et) {}
|
|
|
|
void operator() (HDS& hds) {
|
|
int _idx = 0;
|
|
CGAL::Polyhedron_incremental_builder_3<HDS> pb(hds, true);
|
|
|
|
vector<Point3d> start, end;
|
|
pb.begin_surface(10, 10, 10, Polyhedron_builder::ABSOLUTE_INDEXING);
|
|
|
|
map<Point3d,int> pm;
|
|
|
|
for (unsigned int l = 0; l < mc.items.size(); l++) {
|
|
RList& mseg = mc.items[l];
|
|
|
|
Point3d p(mseg.items[0].getFt(), mseg.items[1].getFt(),
|
|
starttime);
|
|
Point3d q(mseg.items[2].getFt(), mseg.items[3].getFt(),
|
|
endtime);
|
|
|
|
if (pm.count(p) == 0) {
|
|
pm[p] = _idx++;
|
|
pb.add_vertex(p);
|
|
}
|
|
|
|
if (pm.count(q) == 0) {
|
|
pm[q] = _idx++;
|
|
pb.add_vertex(q);
|
|
}
|
|
}
|
|
|
|
for (unsigned int l = 0; l < mc.items.size(); l++) {
|
|
RList& mseg = mc.items[l];
|
|
RList& prev = ((l == 0)?mc.items[mc.items.size()-1] :
|
|
mc.items[l-1]);
|
|
Point3d p(mseg.items[0].getFt(), mseg.items[1].getFt(),
|
|
starttime);
|
|
Point3d q(mseg.items[2].getFt(), mseg.items[3].getFt(),
|
|
endtime);
|
|
Point3d prevp(prev.items[0].getFt(), prev.items[1].getFt(),
|
|
starttime);
|
|
Point3d prevq(prev.items[2].getFt(), prev.items[3].getFt(),
|
|
endtime);
|
|
|
|
if (!(prevp == p)) {
|
|
start.push_back(p);
|
|
}
|
|
if (!(prevq == q)) {
|
|
end.push_back(q);
|
|
}
|
|
|
|
|
|
pb.begin_facet();
|
|
if (prevp == p) {
|
|
pb.add_vertex_to_facet(pm[p]);
|
|
pb.add_vertex_to_facet(pm[q]);
|
|
pb.add_vertex_to_facet(pm[prevq]);
|
|
} else if (prevq == q) {
|
|
pb.add_vertex_to_facet(pm[p]);
|
|
pb.add_vertex_to_facet(pm[q]);
|
|
pb.add_vertex_to_facet(pm[prevp]);
|
|
} else {
|
|
pb.add_vertex_to_facet(pm[p]);
|
|
pb.add_vertex_to_facet(pm[q]);
|
|
pb.add_vertex_to_facet(pm[prevq]);
|
|
pb.add_vertex_to_facet(pm[prevp]);
|
|
}
|
|
pb.end_facet();
|
|
}
|
|
if (start.size() >= 3) {
|
|
pb.begin_facet();
|
|
for (int i = start.size()-1; i >= 0; i--) {
|
|
pb.add_vertex_to_facet(pm[start[i]]);
|
|
}
|
|
pb.end_facet();
|
|
}
|
|
if (end.size() >= 3) {
|
|
pb.begin_facet();
|
|
for (unsigned int i = 0; i < end.size(); i++) {
|
|
pb.add_vertex_to_facet(pm[end[i]]);
|
|
}
|
|
pb.end_facet();
|
|
}
|
|
pb.end_surface();
|
|
}
|
|
};
|
|
|
|
PMRegion PMRegion::fromMRegion (RList reg) {
|
|
Nef_polyhedron np;
|
|
|
|
double off = parsetime(reg.items[4].items[0].items[0].items[0].getString());
|
|
off = 0;
|
|
|
|
RList& urs = reg.items[4];
|
|
|
|
for (unsigned int i = 0; i < urs.items.size(); i++) {
|
|
RList& ur = urs.items[i];
|
|
RList& iv = ur.items[0];
|
|
|
|
|
|
Kernel::FT starttime = parsetime(iv.items[0].getString()) - off;
|
|
Kernel::FT endtime = parsetime(iv.items[1].getString()) - off;
|
|
|
|
if (starttime == endtime)
|
|
continue;
|
|
|
|
RList& fcs = ur.items[1];
|
|
for (unsigned int j = 0; j < fcs.items.size(); j++) {
|
|
RList& fc = fcs.items[j];
|
|
for (unsigned int k = 0; k < fc.items.size(); k++) {
|
|
RList& mc = fc.items[k];
|
|
build_from_mregion<Polyhedron::HalfedgeDS> bm(mc, starttime,
|
|
endtime);
|
|
Polyhedron p;
|
|
|
|
p.delegate(bm);
|
|
CGAL::Polygon_mesh_processing::triangulate_faces(p);
|
|
|
|
Nef_polyhedron nnp(p);
|
|
if (k == 0) {
|
|
Nef_polyhedron ntmp = np + nnp;
|
|
if (ntmp.is_simple())
|
|
np = ntmp;
|
|
else {
|
|
translatedelta(0.0000001, 1, 1, 0, p);
|
|
nnp = Nef_polyhedron(p);
|
|
ntmp = np + nnp;
|
|
if (ntmp.is_simple()) {
|
|
cerr << "Warning: Fixed face" << endl;
|
|
np = ntmp;
|
|
} else
|
|
cerr << "Error: Ignored face" << endl;
|
|
}
|
|
} else {
|
|
Nef_polyhedron ntmp = np - nnp;
|
|
if (ntmp.is_simple())
|
|
np = ntmp;
|
|
else {
|
|
translatedelta(0.0000001, 1, 1, 0, p);
|
|
nnp = Nef_polyhedron(p);
|
|
ntmp = np - nnp;
|
|
if (ntmp.is_simple()) {
|
|
cerr << "Warning: Fixed hole" << endl;
|
|
np = ntmp;
|
|
} else
|
|
cerr << "Error: Ignored hole" << endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PMRegion pmreg;
|
|
np.convert_to_polyhedron(pmreg.polyhedron);
|
|
|
|
return pmreg;
|
|
}
|
|
|
|
|
|
/* Convert a PMRegion to a classical (unit-based) MRegion. */
|
|
|
|
ostream& operator<<(ostream& os, const Seg3d& ms) {
|
|
os << ms.s << " / " << ms.e;
|
|
return os;
|
|
}
|
|
|
|
void MovSeg::reverse () {
|
|
Point_3 tmp;
|
|
tmp = i.s;
|
|
i.s = i.e;
|
|
i.e = tmp;
|
|
tmp = f.s;
|
|
f.s = f.e;
|
|
f.e = tmp;
|
|
}
|
|
|
|
bool MovSeg::isnear (Point_3 a, Point_3 b, Num delta) {
|
|
Num d1 = a.x() - b.x(),
|
|
d2 = a.y() - b.y(),
|
|
d3 = a.z() - b.z();
|
|
if (d1 < 0)
|
|
d1 = -d1;
|
|
if (d2 < 0)
|
|
d2 = -d2;
|
|
if (d3 < 0)
|
|
d3 = -d3;
|
|
return d1 < delta && d2 < delta && d3 < delta;
|
|
}
|
|
|
|
std::vector<MovSeg *>::iterator MovSeg::findNext (std::vector<MovSeg *>& vec) {
|
|
for (std::vector<MovSeg *>::iterator it = vec.begin();
|
|
it != vec.end(); it++) {
|
|
if (isnext(*it))
|
|
return it;
|
|
if (isreversenext(*it)) {
|
|
(*it)->reverse();
|
|
return it;
|
|
}
|
|
}
|
|
return vec.end();
|
|
}
|
|
|
|
std::vector<MovSeg>::iterator MovSeg::findNext (std::vector<MovSeg>& vec) {
|
|
for (std::vector<MovSeg>::iterator it = vec.begin();
|
|
it != vec.end(); it++) {
|
|
if (isnext(*it))
|
|
return it;
|
|
if (isreversenext(*it)) {
|
|
it->reverse();
|
|
return it;
|
|
}
|
|
}
|
|
return vec.end();
|
|
}
|
|
|
|
string MovSeg::ToString() const {
|
|
std::stringstream ss;
|
|
ss << i.s << " / " << i.e << " --- " << f.s << " / " << f.e << endl;
|
|
return ss.str();
|
|
}
|
|
|
|
class MovSegs {
|
|
public:
|
|
set<MovSeg *> segs;
|
|
map<Seg3d,vector<MovSeg *> > segsfwd, segsrev;
|
|
|
|
~MovSegs() {
|
|
int nr = 0;
|
|
for (set<MovSeg *>::iterator it = segs.begin();
|
|
it != segs.end(); it++) {
|
|
delete *it;
|
|
nr++;
|
|
}
|
|
}
|
|
|
|
|
|
void append (MovSeg *ms) {
|
|
segs.insert(ms);
|
|
Seg3d fwd(ms->i.s, ms->f.s);
|
|
Seg3d rev(ms->i.e, ms->f.e);
|
|
|
|
segsfwd[fwd].push_back(ms);
|
|
segsrev[rev].push_back(ms);
|
|
}
|
|
|
|
MovSeg* findNext (MovSeg* ms) {
|
|
Seg3d p(ms->i.e, ms->f.e);
|
|
|
|
map<Seg3d,vector<MovSeg *> >::iterator it;
|
|
it = segsfwd.find(p);
|
|
if (it != segsfwd.end()) {
|
|
for (vector<MovSeg *>::iterator mi = it->second.begin();
|
|
mi != it->second.end(); mi++) {
|
|
set<MovSeg *>::iterator it2 = segs.find(*mi);
|
|
if (it2 != segs.end()) {
|
|
MovSeg *ret = *it2;
|
|
segs.erase(it2);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
it = segsrev.find(p);
|
|
if (it != segsrev.end()) {
|
|
for (vector<MovSeg *>::iterator mi = it->second.begin();
|
|
mi != it->second.end(); mi++) {
|
|
set<MovSeg *>::iterator it2 = segs.find(*mi);
|
|
if (it2 != segs.end()) {
|
|
MovSeg *ret = *it2;
|
|
ret->reverse();
|
|
segs.erase(it2);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
cerr << "Did not find followup" << endl;
|
|
for (auto xx = segsfwd.begin(); xx != segsfwd.end(); xx++) {
|
|
if (!(p == xx->first)) {
|
|
cerr << p << " != " << xx->first << endl;
|
|
} else {
|
|
cerr << p << " == " << xx->first << endl;
|
|
}
|
|
}
|
|
for (set<MovSeg *>::iterator it = segs.begin();
|
|
it != segs.end(); it++) {
|
|
cerr << (*it)->ToString() << endl;
|
|
}
|
|
assert(false);
|
|
return NULL;
|
|
}
|
|
|
|
MovSeg* begin() {
|
|
set<MovSeg *>::iterator it = segs.begin();
|
|
MovSeg* ret = *it;
|
|
segs.erase(it);
|
|
return ret;
|
|
}
|
|
|
|
bool empty() {
|
|
return segs.empty();
|
|
}
|
|
|
|
int size() {
|
|
return segs.size();
|
|
}
|
|
};
|
|
|
|
#define POLY_INITIAL 0
|
|
#define POLY_FINAL 1
|
|
|
|
Polygon makePoly (vector<MovSeg *> m, int initialfinal) {
|
|
Polygon ret;
|
|
|
|
for (unsigned int i = 0; i < m.size(); i++) {
|
|
Point_2 p;
|
|
if (initialfinal == POLY_INITIAL) {
|
|
p = Point_2(m[i]->i.s.x(), m[i]->i.s.y());
|
|
} else {
|
|
p = Point_2(m[i]->f.s.x(), m[i]->f.s.y());
|
|
}
|
|
ret.push_back(p);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool inside (vector<MovSeg *> a, vector<MovSeg *> b) {
|
|
Polygon poly = makePoly(a, POLY_INITIAL);
|
|
if (poly.is_simple()) {
|
|
Point_2 p(b[0]->i.s.x(), b[0]->i.s.y());
|
|
int st = poly.bounded_side(p);
|
|
if (st != CGAL::ON_BOUNDARY)
|
|
return st == CGAL::ON_BOUNDED_SIDE;
|
|
}
|
|
|
|
poly = makePoly(a, POLY_FINAL);
|
|
if (!poly.is_simple())
|
|
return false;
|
|
Point_2 p(b[0]->f.s.x(), b[0]->f.s.y());
|
|
|
|
return poly.bounded_side(p) == CGAL::ON_BOUNDED_SIDE;
|
|
}
|
|
|
|
ostream& operator<<(ostream& os, const MovSegs& ms) {
|
|
for (set<MovSeg *>::iterator it = ms.segs.begin();
|
|
it != ms.segs.end(); it++) {
|
|
os << (*it)->ToString() << endl;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
|
|
static std::vector<std::vector<MovSeg> >sortmcycle(std::vector<MovSeg> movsegs);
|
|
static std::vector<std::vector<MovSeg *> >sortmcycle2(MovSegs movsegs);
|
|
|
|
Triangle::Triangle (Point_3 p1, Point_3 p2, Point_3 p3) {
|
|
if (p1.z() < p2.z() && p1.z() < p3.z()) {
|
|
a = Point_3(p1);
|
|
if (p2.z() < p3.z()) {
|
|
b = Point_3(p2);
|
|
c = Point_3(p3);
|
|
} else {
|
|
b = Point_3(p3);
|
|
c = Point_3(p2);
|
|
}
|
|
} else if (p2.z() < p3.z()) {
|
|
a = Point_3(p2);
|
|
if (p1.z() < p3.z()) {
|
|
b = Point_3(p1);
|
|
c = Point_3(p3);
|
|
} else {
|
|
b = Point_3(p3);
|
|
c = Point_3(p1);
|
|
}
|
|
} else {
|
|
a = Point_3(p3);
|
|
if (p1.z() < p2.z()) {
|
|
b = Point_3(p1);
|
|
c = Point_3(p2);
|
|
} else {
|
|
b = Point_3(p2);
|
|
c = Point_3(p1);
|
|
}
|
|
}
|
|
}
|
|
|
|
int Triangle::between (Num z) {
|
|
return (z >= a.z() && z <= c.z());
|
|
}
|
|
|
|
typedef Kernel::FT Pr[4];
|
|
|
|
Seg3d Triangle::project (Num z) {
|
|
Num p1x, p1y, p1z, p2x, p2y, p2z;
|
|
Point_3 p1, p2;
|
|
|
|
assert (z >= a.z() && z <= c.z());
|
|
if (z == a.z()) {
|
|
p1 = a;
|
|
p1x = a.x();
|
|
if (z == b.z()) {
|
|
p2 = b;
|
|
} else {
|
|
p2 = a;
|
|
}
|
|
} else if (z == c.z()) {
|
|
p1 = c;
|
|
if (z == b.z()) {
|
|
p2 = b;
|
|
} else {
|
|
p2 = c;
|
|
}
|
|
} else {
|
|
Num frac1 = (z - a.z()) / (c.z() - a.z());
|
|
p1x = a.x() + (c.x() - a.x())*frac1;
|
|
p1y = a.y() + (c.y() - a.y())*frac1;
|
|
p1z = z;
|
|
|
|
Point_3 t1, t2;
|
|
if (z < b.z()) {
|
|
t1 = a;
|
|
t2 = b;
|
|
} else {
|
|
t1 = b;
|
|
t2 = c;
|
|
}
|
|
Num frac2 = (z - t1.z())/(t2.z() - t1.z());
|
|
p2x = t1.x() + (t2.x() - t1.x())*frac2;
|
|
p2y = t1.y() + (t2.y() - t1.y())*frac2;
|
|
p2z = z;
|
|
p1 = Point_3(p1x, p1y, p1z);
|
|
p2 = Point_3(p2x, p2y, p2z);
|
|
}
|
|
|
|
return Seg3d(p1, p2);
|
|
}
|
|
|
|
int Triangle::sign (Num n) {
|
|
if (n > 0)
|
|
return 1;
|
|
else if (n == 0)
|
|
return 0;
|
|
else // if (n < 0)
|
|
return -1;
|
|
}
|
|
|
|
MovSeg *Triangle::project (Num z1, Num z2) {
|
|
Seg3d si = project(z1);
|
|
Seg3d sf = project(z2);
|
|
|
|
Num dx1 = si.s.x() - si.e.x();
|
|
Num dy1 = si.s.y() - si.e.y();
|
|
Num dx2 = sf.s.x() - sf.e.x();
|
|
Num dy2 = sf.s.y() - sf.e.y();
|
|
|
|
if (sign(dx1) != sign(dx2) || sign(dy1) != sign(dy2)) {
|
|
sf.reverse();
|
|
}
|
|
MovSeg *ms = new MovSeg(si, sf);
|
|
|
|
return ms;
|
|
}
|
|
|
|
RList PMRegion::toMRegion2(int raw) {
|
|
map<Num, vector<Triangle *> > tri;
|
|
RList uregs;
|
|
|
|
set<Num> zevents;
|
|
int facets = 0;
|
|
int nr = 0;
|
|
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
|
|
for (Facet_iterator f = polyhedron.facets_begin();
|
|
f != polyhedron.facets_end(); f++) {
|
|
Halfedge_facet_circulator hc = f->facet_begin();
|
|
Point_3 p1(hc++->vertex()->point());
|
|
Point_3 p2(hc++->vertex()->point());
|
|
Point_3 p3(hc++->vertex()->point());
|
|
assert(hc == f->facet_begin());
|
|
if (p1.z() == p2.z() && p1.z() == p3.z())
|
|
continue; // All points coplanar to a plane parallel to the xy plane
|
|
Triangle *t = new Triangle(p1, p2, p3);
|
|
nr++;
|
|
Kernel::FT az = t->a.z();
|
|
Kernel::FT bz = t->b.z();
|
|
Kernel::FT cz = t->c.z();
|
|
tri[az].push_back(t);
|
|
zevents.insert(az);
|
|
zevents.insert(bz);
|
|
zevents.insert(cz);
|
|
facets++;
|
|
}
|
|
|
|
vector<Triangle *> curset;
|
|
Num prevz = 0;
|
|
int nrevents = 0;
|
|
nr = 0;
|
|
for (set<Num>::iterator it = zevents.begin(); it != zevents.end(); ++it) {
|
|
Num z = *it;
|
|
vector<Triangle *> triangles = tri[z];
|
|
curset.insert(curset.end(), triangles.begin(), triangles.end());
|
|
if (nrevents++ == 0) {
|
|
prevz = z;
|
|
continue;
|
|
}
|
|
|
|
for (vector<Triangle *>::iterator ti = curset.begin();
|
|
ti != curset.end(); ) {
|
|
if ((*ti)->c.z() < prevz) {
|
|
ti = curset.erase(ti);
|
|
} else {
|
|
ti++;
|
|
}
|
|
}
|
|
|
|
MovSegs msegs;
|
|
for (vector<Triangle *>::iterator ti = curset.begin();
|
|
ti != curset.end(); ti++) {
|
|
if ((*ti)->between(prevz) && (*ti)->between(z)) {
|
|
MovSeg *ms = (*ti)->project(prevz+EPSILON, z-EPSILON);
|
|
msegs.append(ms);
|
|
}
|
|
}
|
|
|
|
std::vector<std::vector<MovSeg *> > cycles = sortmcycle2(msegs);
|
|
RList ureg, mfaces, iv;
|
|
iv.append(timestr(prevz));
|
|
iv.append(timestr(z));
|
|
iv.append(true);
|
|
iv.append(false);
|
|
ureg.append(iv);
|
|
map<int,vector<int> > face2holes;
|
|
set<int> holes;
|
|
for (unsigned int i = 0; i < cycles.size(); i++) {
|
|
for (unsigned int j = 0; j < cycles.size(); j++) {
|
|
if (inside(cycles[i], cycles[j])) {
|
|
face2holes[i].push_back(j);
|
|
holes.insert(j);
|
|
}
|
|
}
|
|
}
|
|
for (unsigned int i = 0; i < cycles.size(); i++) {
|
|
if (holes.find(i) != holes.end()) {
|
|
continue;
|
|
}
|
|
RList mfacewithholes;
|
|
RList mface;
|
|
std::vector<MovSeg *>& cyc = cycles[i];
|
|
for (unsigned int j = 0; j < cyc.size(); j++) {
|
|
MovSeg *ms = cyc[j];
|
|
if (ms->isdegenerated())
|
|
continue;
|
|
RList msrl;
|
|
msrl.append(ms->i.s.x());
|
|
msrl.append(ms->i.s.y());
|
|
msrl.append(ms->f.s.x());
|
|
msrl.append(ms->f.s.y());
|
|
mface.append(msrl);
|
|
}
|
|
mfacewithholes.append(mface);
|
|
vector<int> holes = face2holes[i];
|
|
for (unsigned int h = 0; h < holes.size(); h++) {
|
|
std::vector<MovSeg *>& cyc = cycles[holes[h]];
|
|
RList hole;
|
|
for (unsigned int j = 0; j < cyc.size(); j++) {
|
|
MovSeg *ms = cyc[j];
|
|
if (ms->isdegenerated())
|
|
continue;
|
|
RList msrl;
|
|
msrl.append(ms->i.s.x());
|
|
msrl.append(ms->i.s.y());
|
|
msrl.append(ms->f.s.x());
|
|
msrl.append(ms->f.s.y());
|
|
hole.append(msrl);
|
|
}
|
|
mfacewithholes.append(hole);
|
|
}
|
|
|
|
mfaces.append(mfacewithholes);
|
|
}
|
|
ureg.append(mfaces);
|
|
if (mfaces.items.size() > 0)
|
|
uregs.append(ureg);
|
|
|
|
prevz = z;
|
|
}
|
|
|
|
return raw ? uregs : uregs.obj("mregion", "mregion");
|
|
}
|
|
|
|
RList PMRegion::toMRegion2() {
|
|
return toMRegion2(false);
|
|
}
|
|
|
|
#define DELTA 0.0000001
|
|
|
|
static MovSeg createMSegFromFacet (SHalfedge_const_handle h,
|
|
Kernel::FT min, Kernel::FT max);
|
|
RList PMRegion::toMRegion () {
|
|
bool first = true;
|
|
Kernel::FT prev;
|
|
Nef_polyhedron np(polyhedron);
|
|
set<Kernel::FT> zevents;
|
|
|
|
for (Vertex_const_iterator v = np.vertices_begin();
|
|
v != np.vertices_end(); ++v) {
|
|
zevents.insert(v->point().z());
|
|
}
|
|
|
|
cerr << "Events: " << zevents.size() << endl;
|
|
|
|
RList uregs;
|
|
for (std::set<Kernel::FT>::iterator it = zevents.begin();
|
|
it != zevents.end(); it++) {
|
|
if (!first) {
|
|
RList ureg;
|
|
|
|
RList iv;
|
|
|
|
iv.append(timestr(prev));
|
|
iv.append(timestr(*it));
|
|
iv.append(true);
|
|
iv.append(std::distance(it, zevents.end()) == 1);
|
|
ureg.append(iv);
|
|
|
|
Nef_polyhedron r1 = np
|
|
.intersection(Plane(Point3d(0, 0, prev+DELTA), Vector(0,0, -1)),
|
|
Nef_polyhedron::CLOSED_HALFSPACE);
|
|
Nef_polyhedron result = r1
|
|
.intersection(Plane(Point3d(0, 0, *it-DELTA), Vector(0,0, 1)),
|
|
Nef_polyhedron::CLOSED_HALFSPACE);
|
|
|
|
vector<MovSeg> cycle;
|
|
for (Halffacet_const_iterator f = result.halffacets_begin();
|
|
f != result.halffacets_end(); f++) {
|
|
if (f->is_twin()) continue;
|
|
for (Halffacet_cycle_const_iterator fc =f->facet_cycles_begin();
|
|
fc != f->facet_cycles_end(); fc++) {
|
|
if (fc.is_shalfedge()) {
|
|
MovSeg ms = createMSegFromFacet(fc,
|
|
prev+DELTA, *it-DELTA);
|
|
if (ms.valid) {
|
|
cycle.push_back(ms);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
std::vector<std::vector<MovSeg> > cycles = sortmcycle(cycle);
|
|
RList mfaces;
|
|
for (unsigned int i = 0; i < cycles.size(); i++) {
|
|
RList mfacewithholes;
|
|
RList mface;
|
|
std::vector<MovSeg>& cyc = cycles[i];
|
|
for (unsigned int j = 0; j < cyc.size(); j++) {
|
|
MovSeg& ms = cyc[j];
|
|
RList msrl;
|
|
msrl.append(ms.i.s.x());
|
|
msrl.append(ms.i.s.y());
|
|
msrl.append(ms.f.s.x());
|
|
msrl.append(ms.f.s.y());
|
|
mface.append(msrl);
|
|
}
|
|
mfacewithholes.append(mface);
|
|
mfaces.append(mfacewithholes);
|
|
}
|
|
ureg.append(mfaces);
|
|
if (mfaces.items.size() > 0)
|
|
uregs.append(ureg);
|
|
}
|
|
first = false;
|
|
prev = *it;
|
|
}
|
|
|
|
return uregs.obj("mregion", "mregion");
|
|
}
|
|
|
|
/* Creates a moving segment from a polyhedron surface */
|
|
static MovSeg createMSegFromFacet (SHalfedge_const_handle h, Kernel::FT min,
|
|
Kernel::FT max) {
|
|
SHalfedge_around_facet_const_circulator hc(h), he(hc);
|
|
Kernel::FT prevz;
|
|
bool found = false;
|
|
for (int i = 0, dist = circulator_distance(hc, he); i < dist+1; i++) {
|
|
Kernel::FT z = hc->source()->source()->point().z();
|
|
if (i > 0 && prevz == max && z == min) {
|
|
found = true;
|
|
break;
|
|
}
|
|
hc++;
|
|
prevz = z;
|
|
}
|
|
if (!found) {
|
|
return MovSeg();
|
|
}
|
|
he = hc;
|
|
Point3d is = hc->source()->source()->point(), ie;
|
|
do {
|
|
ie = hc->source()->source()->point();
|
|
hc++;
|
|
} while (hc->source()->source()->point().z() == min);
|
|
Point3d fe = hc->source()->source()->point(), fs;
|
|
do {
|
|
fs = hc->source()->source()->point();
|
|
hc++;
|
|
} while (hc->source()->source()->point().z() == max);
|
|
|
|
return MovSeg(is, ie, fs, fe);
|
|
}
|
|
|
|
/* Sorts the moving segments to cycles */
|
|
static std::vector<std::vector<MovSeg> > sortmcycle
|
|
(std::vector<MovSeg> movsegs) {
|
|
std::vector<std::vector<MovSeg> > ret;
|
|
|
|
while (!movsegs.empty()) {
|
|
std::vector<MovSeg> cycle;
|
|
MovSeg first = *(movsegs.begin());
|
|
cycle.push_back(first);
|
|
MovSeg cur = first;
|
|
movsegs.erase(movsegs.begin());
|
|
Polygon_2 pi, pf;
|
|
Point_2 piprev(0, 0), pifinal(0, 0);
|
|
Point_2 pfprev(0, 0), pffinal(0, 0);
|
|
do {
|
|
std::vector<MovSeg>::iterator it = cur.findNext(movsegs);
|
|
if (it == movsegs.end()) {
|
|
cerr << "Warning: Failed to find next segment" << endl;
|
|
break; // XXX
|
|
}
|
|
assert(it != movsegs.end());
|
|
cur = *it;
|
|
cycle.push_back(cur);
|
|
movsegs.erase(it);
|
|
Point_2 pip(cur.i.s.x(), cur.i.s.y());
|
|
if ((pip != piprev) && (pip != pifinal)) {
|
|
pi.push_back(pip);
|
|
if (pi.size() == 1)
|
|
pifinal = pip;
|
|
}
|
|
piprev = pip;
|
|
Point_2 pfp(cur.f.s.x(), cur.f.s.y());
|
|
if ((pfp != pfprev) && (pfp != pffinal)) {
|
|
pf.push_back(pfp);
|
|
if (pf.size() == 1)
|
|
pffinal = pfp;
|
|
}
|
|
pfprev = pfp;
|
|
|
|
if (cur.isnext(first))
|
|
break;
|
|
} while (1);
|
|
if ((pi.is_simple() && pi.orientation() == CGAL::CLOCKWISE) ||
|
|
(pf.is_simple() && pf.orientation() == CGAL::CLOCKWISE)) {
|
|
std::reverse(cycle.begin(), cycle.end());
|
|
for (unsigned int i = 0; i < cycle.size(); i++)
|
|
cycle[i].reverse();
|
|
}
|
|
ret.push_back(cycle);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sorts the moving segments to cycles */
|
|
static std::vector<std::vector<MovSeg *> > sortmcycle2
|
|
(MovSegs movsegs) {
|
|
std::vector<std::vector<MovSeg *> > ret;
|
|
|
|
while (!movsegs.empty()) {
|
|
std::vector<MovSeg *> cycle;
|
|
MovSeg *first = movsegs.begin();
|
|
cycle.push_back(first);
|
|
MovSeg *cur = first;
|
|
Polygon_2 pi, pf;
|
|
Point_2 piprev(0, 0), pifinal(0, 0);
|
|
Point_2 pfprev(0, 0), pffinal(0, 0);
|
|
do {
|
|
cur = movsegs.findNext(cur);
|
|
cycle.push_back(cur);
|
|
Point_2 pip(cur->i.s.x(), cur->i.s.y());
|
|
if ((pip != piprev) && (pip != pifinal)) {
|
|
pi.push_back(pip);
|
|
if (pi.size() == 1)
|
|
pifinal = pip;
|
|
}
|
|
piprev = pip;
|
|
Point_2 pfp(cur->f.s.x(), cur->f.s.y());
|
|
if ((pfp != pfprev) && (pfp != pffinal)) {
|
|
pf.push_back(pfp);
|
|
if (pf.size() == 1)
|
|
pffinal = pfp;
|
|
}
|
|
pfprev = pfp;
|
|
|
|
if (cur->isnext(first))
|
|
break;
|
|
} while (1);
|
|
if ((pi.is_simple() && pi.orientation() == CGAL::CLOCKWISE) ||
|
|
(pf.is_simple() && pf.orientation() == CGAL::CLOCKWISE)) {
|
|
std::reverse(cycle.begin(), cycle.end());
|
|
for (unsigned int i = 0; i < cycle.size(); i++)
|
|
cycle[i]->reverse();
|
|
}
|
|
ret.push_back(cycle);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Conversion function from and to native pmregion rlist
|
|
format
|
|
|
|
*/
|
|
|
|
PMRegion PMRegion::fromRList (RList& rl) {
|
|
RList& obj = rl.items[4];
|
|
RList& points = obj.items[0];
|
|
RList& facets = obj.items[1];
|
|
std::stringstream off;
|
|
|
|
off << "OFF" << endl;
|
|
off << points.items.size() << " " << facets.items.size() << " 0" << endl;
|
|
for (unsigned int i = 0; i < points.items.size(); i++) {
|
|
RList& point = points.items[i];
|
|
off << setprecision(100) << point.items[0].getFt() << " " <<
|
|
point.items[1].getFt() << " " << point.items[2].getFt() << endl;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < facets.items.size(); i++) {
|
|
RList& facet = facets.items[i];
|
|
off << facet.items.size();
|
|
for (unsigned int j = 0; j < facet.items.size(); j++) {
|
|
off << " " << ((int) facet.items[j].getNr());
|
|
}
|
|
off << endl;
|
|
}
|
|
|
|
return PMRegion::fromOFF(off.str());
|
|
}
|
|
|
|
RList PMRegion::toRList (bool raw) {
|
|
RList pmreg;
|
|
|
|
std::map<Point3d, int> pmap;
|
|
int idx = 0;
|
|
RList points;
|
|
for (Vertex_iterator v = polyhedron.vertices_begin();
|
|
v != polyhedron.vertices_end(); ++v) {
|
|
RList point;
|
|
|
|
Point3d p = v->point();
|
|
pmap[p] = idx++;
|
|
point.append(p.x());
|
|
point.append(p.y());
|
|
point.append(p.z());
|
|
points.append(point);
|
|
}
|
|
pmreg.append(points);
|
|
|
|
RList faces;
|
|
for (Facet_iterator f = polyhedron.facets_begin();
|
|
f != polyhedron.facets_end(); f++) {
|
|
Halfedge_facet_circulator h = f->facet_begin(), he(h);
|
|
|
|
RList face;
|
|
do {
|
|
Point3d p = h->vertex()->point();
|
|
face.append((double)pmap[p]);
|
|
} while (++h != he);
|
|
faces.append(face);
|
|
}
|
|
pmreg.append(faces);
|
|
|
|
return raw ? pmreg : pmreg.obj("pmregion", "pmregion");
|
|
}
|
|
|
|
RList PMRegion::toRList () {
|
|
return toRList(false);
|
|
}
|
|
|
|
void Arrangement2Region(Arrangement::Face_iterator fi, RList& region) {
|
|
for (Arrangement::Hole_iterator fs = fi->holes_begin();
|
|
fs != fi->holes_end(); fs++) {
|
|
RList face;
|
|
|
|
RList maincycle;
|
|
Arrangement::Ccb_halfedge_circulator c = *fs, ec(c);
|
|
do {
|
|
RList point;
|
|
point.append(c->source()->point().x());
|
|
point.append(c->source()->point().y());
|
|
maincycle.append(point);
|
|
} while (++c != ec);
|
|
face.append(maincycle);
|
|
|
|
Arrangement::Face_handle ft = c->twin()->face();
|
|
for (Arrangement::Hole_iterator hi = ft->holes_begin();
|
|
hi != ft->holes_end(); hi++) {
|
|
RList holecycle;
|
|
Arrangement::Ccb_halfedge_circulator hs = *hi, he = hs;
|
|
do {
|
|
RList point;
|
|
point.append(hs->source()->point().x());
|
|
point.append(hs->source()->point().y());
|
|
holecycle.append(point);
|
|
} while (++hs != he);
|
|
face.append(holecycle);
|
|
|
|
Arrangement2Region(hs->twin()->face(), region);
|
|
}
|
|
region.prepend(face);
|
|
}
|
|
}
|
|
|
|
void Arrangement2Region2(Arrangement& arr, RList& region) {
|
|
for (Arrangement::Face_iterator fs = arr.faces_begin();
|
|
fs != arr.faces_end(); fs++) {
|
|
RList face;
|
|
|
|
RList maincycle;
|
|
if (fs->is_unbounded())
|
|
continue;
|
|
Arrangement::Ccb_halfedge_circulator c = fs->outer_ccb(), ec(c);
|
|
do {
|
|
RList point;
|
|
point.append(c->source()->point().x());
|
|
point.append(c->source()->point().y());
|
|
maincycle.append(point);
|
|
} while (++c != ec);
|
|
face.append(maincycle);
|
|
|
|
for (Arrangement::Hole_iterator hi = fs->holes_begin();
|
|
hi != fs->holes_end(); hi++) {
|
|
RList holecycle;
|
|
Arrangement::Ccb_halfedge_circulator hs = *hi, he = hs;
|
|
do {
|
|
RList point;
|
|
point.append(hs->source()->point().x());
|
|
point.append(hs->source()->point().y());
|
|
holecycle.append(point);
|
|
} while (++hs != he);
|
|
face.append(holecycle);
|
|
}
|
|
region.prepend(face);
|
|
}
|
|
}
|
|
|
|
|
|
RList Polygons2Region (vector<Polygon_with_holes_2> polygons) {
|
|
RList faces;
|
|
|
|
for (unsigned int i = 0; i < polygons.size(); i++) {
|
|
RList face;
|
|
RList cycle;
|
|
Polygon_with_holes_2& p = polygons[i];
|
|
for (PG2VI vi = p.outer_boundary().vertices_begin();
|
|
vi != p.outer_boundary().vertices_end(); vi++) {
|
|
RList point;
|
|
point.append(vi->x());
|
|
point.append(vi->y());
|
|
cycle.append(point);
|
|
}
|
|
face.append(cycle);
|
|
for (Hole_const_iterator h = p.holes_begin(); h != p.holes_end(); h++) {
|
|
Polygon_2 po = *h;
|
|
RList hole;
|
|
for (PG2VI vi = po.vertices_begin(); vi != po.vertices_end();vi++) {
|
|
RList point;
|
|
point.append(vi->x());
|
|
point.append(vi->y());
|
|
hole.append(point);
|
|
}
|
|
face.append(hole);
|
|
}
|
|
faces.append(face);
|
|
}
|
|
|
|
return faces.obj("region", "region");
|
|
}
|
|
|
|
static Polygon_2 Cycle2Polygon (RList cycle) {
|
|
vector<Point_2> points;
|
|
for (unsigned int i = 0; i < cycle.items.size(); i++) {
|
|
RList pl = cycle.items[i];
|
|
points.push_back(Point_2(pl.items[0].getFt(), pl.items[1].getFt()));
|
|
}
|
|
Polygon_2 poly(points.begin(), points.end());
|
|
|
|
if (poly.is_simple() && poly.orientation() == CGAL::NEGATIVE)
|
|
poly.reverse_orientation();
|
|
|
|
return poly;
|
|
}
|
|
|
|
static Polygon_with_holes_2 Face2Polygon (RList face) {
|
|
Polygon_2 main = Cycle2Polygon(face.items[0]);
|
|
vector<Polygon_2> holes;
|
|
for (unsigned int i = 1; i < face.items.size(); i++) {
|
|
Polygon_2 hole = Cycle2Polygon(face.items[i]);
|
|
hole.reverse_orientation();
|
|
holes.push_back(hole);
|
|
}
|
|
|
|
return Polygon_with_holes_2(main, holes.begin(), holes.end());
|
|
}
|
|
|
|
vector<Polygon_with_holes_2> Region2Polygons (RList region) {
|
|
vector<Polygon_with_holes_2> ret;
|
|
RList faces = region.items[4];
|
|
for (unsigned int i = 0; i < faces.items.size(); i++) {
|
|
RList face = faces.items[i];
|
|
Polygon_with_holes_2 p = Face2Polygon(face);
|
|
ret.push_back(p);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
typedef Polygon_with_holes_2::Hole_const_iterator Hole_const_iterator;
|
|
|
|
Kernel::FT area (Polygon_with_holes_2 p) {
|
|
Kernel::FT ret = 0;
|
|
|
|
ret += abs(p.outer_boundary().area());
|
|
for (Hole_const_iterator hi = p.holes_begin(); hi != p.holes_end(); hi++) {
|
|
ret -= abs(hi->area());
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Kernel::FT area (vector<Polygon_with_holes_2> ps) {
|
|
Kernel::FT ret = 0;
|
|
|
|
for (unsigned int i = 0; i < ps.size(); i++) {
|
|
ret += area(ps[i]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Kernel::FT area (RList region) {
|
|
return area(Region2Polygons(region));
|
|
}
|
|
|
|
vector<Segment> mpoint2segments (RList& obj) {
|
|
vector<Segment> segs;
|
|
RList& upoints = obj.items[4];
|
|
|
|
for (unsigned int i = 0; i < upoints.items.size(); i++) {
|
|
RList& upoint = upoints.items[i];
|
|
|
|
RList& iv = upoint.items[0];
|
|
double z1 = parsetime(iv.items[0].getString());
|
|
double z2 = parsetime(iv.items[1].getString());
|
|
|
|
RList& points = upoint.items[1];
|
|
Kernel::FT x1 = points.items[0].getFt();
|
|
Kernel::FT y1 = points.items[1].getFt();
|
|
Kernel::FT x2 = points.items[2].getFt();
|
|
Kernel::FT y2 = points.items[3].getFt();
|
|
|
|
Point3d p(x1, y1, z1);
|
|
Point3d q(x2, y2, z2);
|
|
|
|
segs.push_back(Segment(p, q));
|
|
}
|
|
|
|
return segs;
|
|
}
|
|
|
|
/* Convert a Nef polyhedron to a normal polyhedron */
|
|
Polyhedron nef2polyhedron (Nef_polyhedron np) {
|
|
Polyhedron p;
|
|
|
|
// If the polyhedron is simple, it can be converted directly
|
|
if (np.is_simple()) {
|
|
np.convert_to_polyhedron(p);
|
|
return p;
|
|
}
|
|
|
|
// Otherwise, a polygon soup has to be created
|
|
std::vector<Point3d> points;
|
|
std::vector<std::vector<std::size_t> > polygons;
|
|
for(Nef_polyhedron::Halffacet_const_iterator
|
|
f = np.halffacets_begin (),
|
|
end = np.halffacets_end();
|
|
f != end; ++f) {
|
|
if(f->is_twin()) continue;
|
|
for(Nef_polyhedron::Halffacet_cycle_const_iterator
|
|
fc = f->facet_cycles_begin(),
|
|
end = f->facet_cycles_end();
|
|
fc != end; ++fc)
|
|
{
|
|
if ( fc.is_shalfedge() )
|
|
{
|
|
Nef_polyhedron::SHalfedge_const_handle h = fc;
|
|
Nef_polyhedron::SHalfedge_around_facet_const_circulator hc(h),
|
|
he(hc);
|
|
std::vector<std::size_t> face;
|
|
CGAL_For_all(hc,he) {
|
|
Nef_polyhedron::SVertex_const_handle v = hc->source();
|
|
const Nef_polyhedron::Point_3& point = v->source()->point();
|
|
std::vector<Point3d>::iterator it =
|
|
find(points.begin(), points.end(), point);
|
|
int idx = std::distance(points.begin(), it);
|
|
if (it == points.end())
|
|
points.push_back(point);
|
|
face.push_back(idx);
|
|
}
|
|
polygons.push_back(face);
|
|
}
|
|
}
|
|
}
|
|
|
|
// The soup has to be oriented, converted to a mesh and triangulated
|
|
CGAL::Polygon_mesh_processing::orient_polygon_soup(points, polygons);
|
|
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points,
|
|
polygons, p);
|
|
CGAL::Polygon_mesh_processing::triangulate_faces(p);
|
|
// Just for testing, convert to Nef and back
|
|
Nef_polyhedron tmp(p);
|
|
tmp.convert_to_polyhedron(p);
|
|
|
|
return p;
|
|
}
|
|
|
|
static Nef_polyhedron cycle2polyhedron (RList cycle, Kernel::FT instant1,
|
|
Kernel::FT instant2, Kernel::FT xoff) {
|
|
std::vector<Point3d> xpoints;
|
|
std::vector<std::vector<std::size_t> > xpolygons;
|
|
std::map<Point3d, int> points2index;
|
|
int idx = 0;
|
|
|
|
std::vector<std::size_t> top, bottom;
|
|
unsigned int sz = cycle.items.size();
|
|
for (unsigned int i = 0; i < sz; i++) {
|
|
std::vector<std::size_t> facet;
|
|
|
|
RList prl1 = cycle.items[i];
|
|
RList prl2 = cycle.items[(i+1)%sz];
|
|
|
|
Point3d p1(prl1.items[0].getFt(), prl1.items[1].getFt(), instant1);
|
|
Point3d p2(prl2.items[0].getFt(), prl2.items[1].getFt(), instant1);
|
|
Point3d p3(prl2.items[0].getFt()+xoff, prl2.items[1].getFt(), instant2);
|
|
Point3d p4(prl1.items[0].getFt()+xoff, prl1.items[1].getFt(), instant2);
|
|
|
|
if (points2index.count(p1) == 0) {
|
|
xpoints.push_back(p1);
|
|
points2index[p1] = idx;
|
|
facet.push_back(idx++);
|
|
} else {
|
|
facet.push_back(points2index[p1]);
|
|
}
|
|
if (points2index.count(p2) == 0) {
|
|
xpoints.push_back(p2);
|
|
points2index[p2] = idx;
|
|
facet.push_back(idx++);
|
|
} else {
|
|
facet.push_back(points2index[p2]);
|
|
}
|
|
if (points2index.count(p3) == 0) {
|
|
xpoints.push_back(p3);
|
|
points2index[p3] = idx;
|
|
facet.push_back(idx++);
|
|
} else {
|
|
facet.push_back(points2index[p3]);
|
|
}
|
|
if (points2index.count(p4) == 0) {
|
|
xpoints.push_back(p4);
|
|
points2index[p4] = idx;
|
|
facet.push_back(idx++);
|
|
} else {
|
|
facet.push_back(points2index[p4]);
|
|
}
|
|
|
|
bottom.push_back(points2index[p1]);
|
|
top.push_back(points2index[p4]);
|
|
xpolygons.push_back(facet);
|
|
}
|
|
|
|
std::reverse(top.begin(), top.end());
|
|
xpolygons.push_back(top);
|
|
xpolygons.push_back(bottom);
|
|
|
|
Polyhedron p;
|
|
CGAL::Polygon_mesh_processing::orient_polygon_soup(xpoints, xpolygons);
|
|
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(xpoints,
|
|
xpolygons, p);
|
|
CGAL::Polygon_mesh_processing::triangulate_faces(p);
|
|
|
|
return Nef_polyhedron(p);
|
|
}
|
|
|
|
|
|
|
|
static Nef_polyhedron face2polyhedron (RList face, Kernel::FT instant1,
|
|
Kernel::FT instant2, Kernel::FT xoff) {
|
|
RList main = face.items[0];
|
|
Nef_polyhedron np = cycle2polyhedron(main, instant1, instant2, xoff);
|
|
for (unsigned int i = 1; i < face.items.size(); i++) {
|
|
RList hole = face.items[i];
|
|
Nef_polyhedron nphole = cycle2polyhedron(hole,instant1, instant2, xoff);
|
|
np = np - nphole;
|
|
}
|
|
|
|
return np;
|
|
}
|
|
|
|
Nef_polyhedron region2nefpolyhedron (RList reg, Kernel::FT instant1,
|
|
Kernel::FT instant2, Kernel::FT xoff) {
|
|
RList faces = reg.items[4];
|
|
Nef_polyhedron np;
|
|
for (unsigned int i = 0; i < faces.items.size(); i++) {
|
|
RList face = faces.items[i];
|
|
Nef_polyhedron npface = face2polyhedron(face, instant1, instant2, xoff);
|
|
np = np + npface;
|
|
}
|
|
|
|
return np;
|
|
}
|
|
|
|
PMRegion PMRegion::fromRegion (RList reg, Kernel::FT instant1,
|
|
Kernel::FT instant2, Kernel::FT xoff) {
|
|
PMRegion ret;
|
|
Nef_polyhedron np = region2nefpolyhedron(reg, instant1, instant2, xoff);
|
|
np.convert_to_polyhedron(ret.polyhedron);
|
|
|
|
return ret;
|
|
}
|
|
|
|
}
|