Files
secondo/Algebras/PMRegion/pmregion/PMRegion_helpers.cpp
2026-01-23 17:03:45 +08:00

373 lines
9.8 KiB
C++

/*
* This file is part of libpmregion
*
* File: PMRegion\_helpers.cpp
* Author: Florian Heinz <fh@sysv.de>
1 Helper functions
Date/Time conversion
Range processing
*/
#include "PMRegion_internal.h"
#include <sstream>
#include <iomanip>
#include <map>
#include <ctime>
using namespace std;
using namespace pmr;
namespace pmr {
/*
Helper functions for converting date/time strings into a double
representing the ms since unix epoch
*/
static double utctime (struct tm *tm) {
char *tz;
double ret;
tz = getenv("TZ");
setenv("TZ", "UTC", 1);
tzset();
ret = mktime(tm);
if (tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
return ret;
}
double parsetime (std::string str) {
struct tm tm;
unsigned int msec;
char sep; // Separator, space or -
tm.tm_year = tm.tm_mon = tm.tm_mday = 0;
tm.tm_sec = tm.tm_min = tm.tm_hour = tm.tm_isdst = msec = 0;
int st = sscanf(str.c_str(), "%u-%u-%u%c%u:%u:%u.%u",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &sep,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec,
&msec);
if (st < 3) {
return atof(str.c_str());
}
tm.tm_year -= 1900; // struct tm expects years since 1900
tm.tm_mon--; // struct tm expects months to be numbered from 0 - 11
double ret = utctime(&tm) * 1000 + msec;
return ret;
}
string timestr(double t) {
struct tm *tm;
char buf[32], ret[40];
time_t ti;
ti = t/1000;
char *tz;
tz = getenv("TZ");
setenv("TZ", "UTC", 1);
tzset();
tm = gmtime(&ti);
if (tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
strftime(buf, sizeof(buf), "%F-%T", tm);
sprintf(ret, "%s.%03d", buf, (int) fmod(t,1000));
return ret;
}
string timestr(Kernel::FT t) {
return timestr(::CGAL::to_double(t));
}
template <typename T> void Range<T>::addrange(T a, T b) {
if (a > b)
std::swap(a, b);
typename std::map<T, T>::iterator it1 = range.upper_bound(a);
if (it1 != range.begin() && (--it1,it1++)->second >= a)
it1--;
if (it1 != range.end() && it1->first < a)
a = it1->first;
typename std::map<T, T>::iterator it2(it1);
while (it2 != range.end() && it2->first <= b)
it2++;
if (it2 != range.begin() && (--it2,it2++)->second > b)
b = (--it2,it2++)->second;
range.erase(it1, it2);
range[a] = b;
}
template <typename T> void Range<T>::print() {
typename std::map<T, T>::iterator it = range.begin();
while (it != range.end()) {
cerr << it->first << " - " << it->second << endl;
it++;
}
}
std::set<Kernel::FT> getZEvents (Polyhedron p, Kernel::FT mindiff) {
std::set<Kernel::FT> zevents;
Kernel::FT max;
bool first = true;
for (Vertex_iterator v = p.vertices_begin(); v != p.vertices_end(); ++v) {
Kernel::FT z = v->point().z();
if (first) {
first = false;
max = z;
}
if (max < z) max = z;
zevents.insert(v->point().z());
}
first = true;
Kernel::FT prev;
for (std::set<Kernel::FT>::iterator it = zevents.begin();
it != zevents.end(); ) {
Kernel::FT cur = *it;
if (!first && cur - prev < mindiff) {
it = zevents.erase(it);
continue;
}
first = false;
prev = cur;
++it;
}
zevents.insert(max);
return zevents;
}
std::set<Kernel::FT> getZEvents (Polyhedron p) {
return getZEvents(p, -1);
}
pair<Kernel::FT, Kernel::FT> PMRegion::minmaxz() {
Kernel::FT min = 0, max = 0;
for (Vertex_iterator v = polyhedron.vertices_begin();
v != polyhedron.vertices_end(); ++v) {
Point3d p = v->point();
Kernel::FT z = p.z();
if (z != 0 && (z < min || min == 0))
min = z;
if (z > max)
max = z;
}
return pair<Kernel::FT, Kernel::FT>(min, max);
}
pair<Point3d, Point3d> PMRegion::boundingbox() {
Kernel::FT minx, miny, minz, maxx, maxy, maxz;
bool first = true;
for (Vertex_iterator v = polyhedron.vertices_begin();
v != polyhedron.vertices_end(); ++v) {
Point3d p = v->point();
Kernel::FT x = p.x();
Kernel::FT y = p.y();
Kernel::FT z = p.z();
if (first) {
minx = x;
maxx = x;
miny = y;
maxy = y;
minz = z;
maxz = z;
first = false;
} else {
if (x < minx) minx = x;
if (x > maxx) maxx = x;
if (y < miny) miny = y;
if (y > maxy) maxy = y;
if (z < minz) minz = z;
if (z > maxz) maxz = z;
}
}
return pair<Point3d, Point3d>(Point3d(minx, miny, minz),
Point3d(maxx, maxy, maxz));
}
void PMRegion::analyze() {
vector<pair<Kernel::FT,Kernel::FT> > ranges;
for (Facet_iterator f = polyhedron.facets_begin();
f != polyhedron.facets_end(); f++) {
Halfedge_facet_circulator hc = f->facet_begin();
Kernel::FT min, max;
min = max = hc->vertex()->point().z();
while (++hc != f->facet_begin()) {
Kernel::FT z = hc->vertex()->point().z();
if (z < min)
min = z;
if (z > max)
max = z;
}
if (min != max)
ranges.push_back(pair<Kernel::FT, Kernel::FT>(min, max));
}
std::set<Kernel::FT> zevents = getZEvents(polyhedron);
std::set<Kernel::FT>::iterator it = zevents.begin();
Kernel::FT prev = *it;
int sum = 0;
while (++it != zevents.end()) {
Kernel::FT z = *it;
Kernel::FT med = (z+prev)/2;
int count = 0;
for (std::vector<pair<Kernel::FT,Kernel::FT> >::iterator ri =
ranges.begin(); ri != ranges.end(); ++ri) {
if (ri->first < med && ri->second > med) {
count++;
sum++;
}
}
prev = z;
}
int vertices = distance(polyhedron.vertices_begin(),
polyhedron.vertices_end());
int facets = distance(polyhedron.facets_begin(), polyhedron.facets_end());
int units = zevents.size()-1;
int msegs = sum;
cerr << vertices << ", " << facets << ", "<< units << ", " << msegs << endl;
}
#ifndef PMREGION_DISABLE_COVERDURATION
set<Segment_2, seg_compare> getprojectedsegments(Polyhedron polyhedron);
list<Segment_2> getsubsegments (set<Segment_2, seg_compare> segs);
Arrangement getarrangementfromsegments(list<Segment_2> segs);
void PMRegion::openscad(string filename) {
Kernel::FT zmin, zmax;
for (Point_iterator pi = polyhedron.points_begin();
pi != polyhedron.points_end(); ++pi) {
Kernel::FT z = pi->z();
if (pi == polyhedron.points_begin()) {
zmin = z;
zmax = z;
} else {
if (z < zmin)
zmin = z;
if (z > zmax)
zmax = z;
}
}
ofstream scad;
scad.open(filename + ".scad");
scad << "scale([1, 1, 0.0005]) {" << endl
<< " color(polycol) import(\"" << filename << ".off\");" << endl
<< "}" << endl
;
scad.close();
scad.open(filename + "poles.scad");
scad << "polecol = \"red\";" << endl
<< "polediameter = 2;" << endl
<< "polycol = \"yellow\";" << endl
;
scad << "module pole (x, y, zmin, zmax) {" << endl
<< " color(polecol)" << endl
<< " translate([x, y, zmin-(zmax-zmin)*0.05])" << endl
<< " cylinder(d=polediameter,h=(zmax-zmin)*1.1);" << endl
<< "}" << endl << endl
;
scad << "scale([1, 1, 0.0005]) {" << endl;
for (Point_iterator pi = polyhedron.points_begin();
pi != polyhedron.points_end(); ++pi) {
Kernel::FT x = pi->x();
Kernel::FT y = pi->y();
scad << " pole(" << x << ", " << y << ", " << zmin << ", " <<
zmax << ");" << endl;
}
scad << "}" << endl;
scad.close();
scad.open(filename + ".off");
scad << polyhedron;
scad.close();
set<Segment_2, seg_compare> _segs = getprojectedsegments(polyhedron);
list<Segment_2> segs = getsubsegments(_segs);
scad.open(filename + "mesh.scad");
scad << "include <mypoly.scad>" << endl;
Arrangement arr = getarrangementfromsegments(segs);
Arrangement::Face_const_iterator fit;
Arrangement::Ccb_halfedge_const_circulator curr;
for (fit = arr.faces_begin(); fit != arr.faces_end(); ++fit) {
if (!fit->is_unbounded()) {
curr = fit->outer_ccb();
Polygon poly;
scad << "mypoly([";
do {
Point2d p2d = curr->target()->point();
scad << "[" << p2d.x() << "," << p2d.y() << "]";
++curr;
if (curr != fit->outer_ccb()) {
scad << ",";
}
} while (curr != fit->outer_ccb());
scad << "]);" << endl;
}
}
scad.close();
}
#endif
void PMRegion::toFile(string filename) {
ofstream out;
out.open(filename);
out << toRList().ToString();
out.close();
}
// Keep the linker happy
void rangeinstance () {
Range<Kernel::FT> dummy;
dummy.addrange(0, 0);
}
void translatedelta(Kernel::FT limit, bool x, bool y, bool z, Polyhedron& p) {
Kernel::FT dx, dy, dz;
static int seeded = 0;
if (!seeded) {
srand48(time(NULL));
seeded = 1;
}
double d = drand48()-0.5;
if (d >= 0 && d < 0.2)
d += 0.2;
else if (d <= 0 && d > 0.2)
d -= 0.2;
dx = x ? d*limit*2 : 0;
dy = y ? d*limit*2 : 0;
dz = z ? d*limit*2 : 0;
cerr << "DX: " << std::setprecision(20) << dx << endl;
Kernel::Vector_3 translate(dx, dy, dz);
for (Polyhedron::Vertex_iterator v = p.vertices_begin();
v != p.vertices_end(); v++) {
v->point() = v->point() + translate;
}
}
}