1
// © 2013 Jan Elias, http://www.fce.vutbr.cz/STM/elias.j/, elias.j@fce.vutbr.cz
2
// https://www.vutbr.cz/www_base/gigadisk.php?i=95194aa9a
6
#include"Polyhedra.hpp"
8
#define _USE_MATH_DEFINES
11
//EMPRIRICAL CONSTANTS - ADJUST IF SEGMENTATION FAULT OCCUR, IT IS A PROBLEM OF CGAL. THESE ARE USED TO CHECK CGAL IMPUTS
12
//DISTANCE_LIMIT controls numerical issues in calculating intersection. It should be small enough to neglect only extremely small overlaps, but large enough to prevent errors during computation of convex hull
13
#define DISTANCE_LIMIT 1E-11 //-11
14
//MERGE_PLANES_LIMIT - if two facets of two intersecting polyhedron differ less, then they are treated ose one only
15
#define MERGE_PLANES_LIMIT 1E-18 //18
16
//SIMPLIFY_LIMIT - if two facets of one polyhedron differ less, then they are joint into one facet
17
#define SIMPLIFY_LIMIT 1E-20 //19
18
//FIND_NORMAL_LIMIT - to determine which facet of intersection belongs to which polyhedron
19
#define FIND_NORMAL_LIMIT 1E-40
22
//**********************************************************************************
23
//return volume and centroid of polyhedron
25
bool P_volume_centroid(Polyhedron P, double * volume, Vector3r * centroid){
28
Vector3r basepoint = FromCGALPoint(P.vertices_begin()->point());
32
(*centroid) = Vector3r(0.,0.,0.);
34
//compute centroid and volume
35
for (Polyhedron::Facet_iterator fIter = P.facets_begin(); fIter != P.facets_end(); fIter++){
36
Polyhedron::Halfedge_around_facet_circulator hfc0;
37
hfc0 = fIter->facet_begin();
38
int n = fIter->facet_degree();
39
A = FromCGALPoint(hfc0->vertex()->point());
40
C = FromCGALPoint(hfc0->next()->vertex()->point());
41
for (int i=2; i<n; i++){
44
C = FromCGALPoint(hfc0->next()->vertex()->point());
45
vtet = std::abs((basepoint-C).dot((A-C).cross(B-C)))/6.;
47
*centroid = *centroid + (basepoint+A+B+C) / 4. * vtet;
50
*centroid = *centroid/(*volume);
54
//**********************************************************************************
55
//STOLEN FROM TETRA body of Vaclav Smilauer
57
/*! Calculates tetrahedron inertia relative to the origin (0,0,0), with unit density (scales linearly).
59
See article F. Tonon, "Explicit Exact Formulas for the 3-D Tetrahedron Inertia Tensor in Terms of its Vertex Coordinates", http://www.scipub.org/fulltext/jms2/jms2118-11.pdf
62
//Centroid MUST be [0,0,0]
63
Matrix3r TetraInertiaTensor(Vector3r av,Vector3r bv,Vector3r cv,Vector3r dv){
77
// Jacobian of transformation to the reference 4hedron
78
double detJ=(x2-x1)*(y3-y1)*(z4-z1)+(x3-x1)*(y4-y1)*(z2-z1)+(x4-x1)*(y2-y1)*(z3-z1)
79
-(x2-x1)*(y4-y1)*(z3-z1)-(x3-x1)*(y2-y1)*(z4-z1)-(x4-x1)*(y3-y1)*(z2-z1);
81
double a=detJ*(y1*y1+y1*y2+y2*y2+y1*y3+y2*y3+
82
y3*y3+y1*y4+y2*y4+y3*y4+y4*y4+z1*z1+z1*z2+
83
z2*z2+z1*z3+z2*z3+z3*z3+z1*z4+z2*z4+z3*z4+z4*z4)/60.;
84
double b=detJ*(x1*x1+x1*x2+x2*x2+x1*x3+x2*x3+x3*x3+
85
x1*x4+x2*x4+x3*x4+x4*x4+z1*z1+z1*z2+z2*z2+z1*z3+
86
z2*z3+z3*z3+z1*z4+z2*z4+z3*z4+z4*z4)/60.;
87
double c=detJ*(x1*x1+x1*x2+x2*x2+x1*x3+x2*x3+x3*x3+x1*x4+
88
x2*x4+x3*x4+x4*x4+y1*y1+y1*y2+y2*y2+y1*y3+
89
y2*y3+y3*y3+y1*y4+y2*y4+y3*y4+y4*y4)/60.;
90
// a' in the article etc.
91
double a__=detJ*(2*y1*z1+y2*z1+y3*z1+y4*z1+y1*z2+
92
2*y2*z2+y3*z2+y4*z2+y1*z3+y2*z3+2*y3*z3+
93
y4*z3+y1*z4+y2*z4+y3*z4+2*y4*z4)/120.;
94
double b__=detJ*(2*x1*z1+x2*z1+x3*z1+x4*z1+x1*z2+
95
2*x2*z2+x3*z2+x4*z2+x1*z3+x2*z3+2*x3*z3+
96
x4*z3+x1*z4+x2*z4+x3*z4+2*x4*z4)/120.;
97
double c__=detJ*(2*x1*y1+x2*y1+x3*y1+x4*y1+x1*y2+
98
2*x2*y2+x3*y2+x4*y2+x1*y3+x2*y3+2*x3*y3+
99
x4*y3+x1*y4+x2*y4+x3*y4+2*x4*y4)/120.;
121
//**********************************************************************************
122
//distace of point from a plane (squared) with sign
123
double Oriented_squared_distance(Plane P, CGALpoint x){
124
double h = P.a()*x.x()+P.b()*x.y()+P.c()*x.z()+P.d();
125
return ((h>0.)-(h<0.))*pow(h,2)/(CGALvector(P.a(),P.b(),P.c())).squared_length();
128
//**********************************************************************************
129
// test if point is inside polyhedra in strong sence, i.e. boundary location is not enough
130
bool Is_inside_Polyhedron(Polyhedron P, CGALpoint inside){
131
Polyhedron::Plane_iterator pi;
132
for(pi=P.planes_begin(); pi!=P.planes_end(); ++pi){
133
if( ! pi->has_on_negative_side(inside)) return false;
138
//**********************************************************************************
139
// test if point is inside polyhedra not closer than lim to its boundary
140
bool Is_inside_Polyhedron(Polyhedron P, CGALpoint inside, double lim){
141
Polyhedron::Plane_iterator pi;
143
for(pi=P.planes_begin(); pi!=P.planes_end(); ++pi){
144
if(Oriented_squared_distance(*pi, inside)>-lim) return false;
149
//**********************************************************************************
150
//test if two polyhedron intersect
151
bool do_intersect(Polyhedron A, Polyhedron B){
152
std::vector<int> sep_plane;
153
sep_plane.assign(3,0);
154
return do_intersect(A, B, sep_plane);
157
//**********************************************************************************
158
//test if two polyhedron intersect based on previous data
159
bool do_intersect(Polyhedron A, Polyhedron B, std::vector<int> &sep_plane){
163
//check previous separation plane
164
switch (sep_plane[0]){
165
case 1: //separation plane was previously determined as sep_plane[2]-th plane of A polyhedron
167
if(unlikely((unsigned) sep_plane[2]>=A.size_of_facets())) break;
168
Polyhedron::Facet_iterator fIter = A.facets_begin();
169
for (int i=0; i<sep_plane[2]; i++) ++fIter;
171
for (Polyhedron::Vertex_iterator vIter = B.vertices_begin(); vIter != B.vertices_end(); ++vIter){
172
if (! fIter->plane().has_on_positive_side(vIter->point())) {found = false; break;};
174
if(found) return false;
177
case 2: //separation plane was previously determined as sep_plane[2]-th plane of B polyhedron
179
if(unlikely((unsigned) sep_plane[2]>=B.size_of_facets())) break;
180
Polyhedron::Facet_iterator fIter = B.facets_begin();
181
for (int i=0; i<sep_plane[2]; i++) ++fIter;
183
for (Polyhedron::Vertex_iterator vIter = A.vertices_begin(); vIter != A.vertices_end(); ++vIter){
184
if (! fIter->plane().has_on_positive_side(vIter->point())) {found = false; break;};
186
if(found) return false;
189
case 3: //separation plane was previously given by sep_plane[1]-th and sep_plane[2]-th edge of A & B polyhedrons
191
if(unlikely((unsigned) sep_plane[1]>=A.size_of_halfedges()/2)) break;
192
if(unlikely((unsigned) sep_plane[2]>=B.size_of_halfedges()/2)) break;
193
Polyhedron::Edge_iterator eIter1 = A.edges_begin();
194
Polyhedron::Edge_iterator eIter2 = B.edges_begin();
195
for (int i=0; i<sep_plane[1]; i++) ++eIter1;
196
for (int i=0; i<sep_plane[2]; i++) ++eIter2;
198
Plane X(eIter1->vertex()->point(),CGAL::cross_product((eIter1->vertex()->point() - eIter1->opposite()->vertex()->point()),(eIter2->vertex()->point() - eIter2->opposite()->vertex()->point())));
199
if (!X.has_on_positive_side(B.vertices_begin()->point())) X = X.opposite();
201
double lim = pow(DISTANCE_LIMIT,2);
202
for (Polyhedron::Vertex_iterator vIter = A.vertices_begin(); vIter != A.vertices_end(); ++vIter){
203
if (Oriented_squared_distance(X, vIter->point())>lim) {found = false; break;};
205
for (Polyhedron::Vertex_iterator vIter = B.vertices_begin(); vIter != B.vertices_end(); ++vIter){
206
if (! X.has_on_positive_side(vIter->point())) {found = false; break;};
208
if(found) return false;
213
//regular test with no previous information about separating plane
214
//test all planes from A
216
for (Polyhedron::Facet_iterator fIter = A.facets_begin(); fIter != A.facets_end(); fIter++, i++){
218
for (Polyhedron::Vertex_iterator vIter = B.vertices_begin(); vIter != B.vertices_end(); ++vIter){
219
if (! fIter->plane().has_on_positive_side(vIter->point())) {found = false; break;};
221
if(found) {sep_plane[0] = 1; sep_plane[1] = 1; sep_plane[2] = i; return false;}
223
//test all planes from B
225
for (Polyhedron::Facet_iterator fIter = B.facets_begin(); fIter != B.facets_end(); fIter++, i++){
227
for (Polyhedron::Vertex_iterator vIter = A.vertices_begin(); vIter != A.vertices_end(); ++vIter){
228
if (! fIter->plane().has_on_positive_side(vIter->point())) {found = false; break;};
230
if(found) {sep_plane[0] = 2; sep_plane[1] = 2; sep_plane[2] = i; return false;}
232
//test all pairs of edges from A & B
235
double lim = pow(DISTANCE_LIMIT,2);
237
for (Polyhedron::Edge_iterator eIter1 = A.edges_begin(); eIter1 != A.edges_end(); ++eIter1, i++){
238
vA = eIter1->vertex()->point() - eIter1->opposite()->vertex()->point();
240
for (Polyhedron::Edge_iterator eIter2 = B.edges_begin(); eIter2 != B.edges_end(); ++eIter2, j++){
242
X = Plane(eIter1->vertex()->point(),CGAL::cross_product(vA,(eIter2->vertex()->point() - eIter2->opposite()->vertex()->point()) ));
243
if (!X.has_on_positive_side(B.vertices_begin()->point())) X = X.opposite();
244
for (Polyhedron::Vertex_iterator vIter = A.vertices_begin(); vIter != A.vertices_end(); ++vIter){
245
if (Oriented_squared_distance(X, vIter->point())>lim) {found = false; break;};
247
for (Polyhedron::Vertex_iterator vIter = B.vertices_begin(); vIter != B.vertices_end(); ++vIter){
248
if (! X.has_on_positive_side(vIter->point())) {found = false; break;};
250
if(found) {sep_plane[0] = 3; sep_plane[1] = i; sep_plane[2] = j; return false;}
258
//**********************************************************************************
259
//norm of difference between two planes
260
double PlaneDifference(const Plane &a, const Plane &b){
261
double la = sqrt(pow(a.a(),2) + pow(a.b(),2) + pow(a.c(),2) + pow(a.d(),2));
262
double lb = sqrt(pow(b.a(),2) + pow(b.b(),2) + pow(b.c(),2) + pow(b.d(),2));
263
return pow(a.a()/la-b.a()/lb,2) + pow(a.b()/la-b.b()/lb,2) + pow(a.c()/la-b.c()/lb,2) + pow(a.d()/la-b.d()/lb,2);
265
//in case we do not care of the orientation
266
//return min(pow(a.a()/la-b.a()/lb,2) + pow(a.b()/la-b.b()/lb,2) + pow(a.c()/la-b.c()/lb,2) + pow(a.d()/la-b.d()/lb,2),pow(a.a()/la+b.a()/lb,2) + pow(a.b()/la+b.b()/lb,2) + pow(a.c()/la+b.c()/lb,2) + pow(a.d()/la+b.d()/lb,2));
269
//**********************************************************************************
270
//connect triagular facets if possible
271
Polyhedron Simplify(Polyhedron P, double limit){
272
bool elimination = true;
275
for (Polyhedron::Edge_iterator hei = P.edges_begin(); hei!=P.edges_end(); ++hei){
276
if (PlaneDifference(hei->facet()->plane(),hei->opposite()->facet()->plane()) < limit){
277
if (hei->vertex()->vertex_degree() < 3) hei = P.erase_center_vertex(hei);
278
else if(hei->opposite()->vertex()->vertex_degree() < 3) hei = P.erase_center_vertex(hei->opposite());
279
else hei = P.join_facet(hei);
285
if (P.size_of_facets() < 4) P.clear();
289
//**********************************************************************************
290
//list of facets + edges
291
void PrintPolyhedron(Polyhedron P){
293
cout << "*** faces ***" << endl;
294
for (Polyhedron::Facet_iterator fIter = P.facets_begin(); fIter!=P.facets_end(); ++fIter){
295
Polyhedron::Halfedge_around_facet_circulator hfc0;
296
hfc0 = fIter->facet_begin();
297
int n = fIter->facet_degree();
298
A = FromCGALPoint(hfc0->vertex()->point());
299
C = FromCGALPoint(hfc0->next()->vertex()->point());
300
for (int i=2; i<n; i++){
303
C = FromCGALPoint(hfc0->next()->vertex()->point());
304
cout << A << " "<< B << " "<< C << endl;
307
cout << "*** edges ***" << endl;
308
for (Polyhedron::Edge_iterator hei = P.edges_begin(); hei!=P.edges_end(); ++hei){
309
cout << hei->vertex()->point() << " " << hei->opposite()->vertex()->point() << endl;
313
//**********************************************************************************
315
void PrintPolyhedronFacets(Polyhedron P){
317
for (Polyhedron::Facet_iterator fIter = P.facets_begin(); fIter!=P.facets_end(); ++fIter){
318
cout << "***" << endl;
319
Polyhedron::Halfedge_around_facet_circulator hfc0;
320
hfc0 = fIter->facet_begin();
321
int n = fIter->facet_degree();
322
for (int i = 0; i<n; ++hfc0, i++){
323
cout << hfc0->vertex()->point() << endl;
328
//**********************************************************************************
329
//calculate intersection of three planes (exceptional cases not checked) - not in use, can be deleted
330
CGALpoint PlaneIntersection( Plane a, Plane b, Plane c){
336
Vector3r x = A.inverse()*Vector3r(-a.d(),-b.d(),-c.d());
337
return CGALpoint(x.x(),x.y(),x.z());
340
//**********************************************************************************
341
//solve system of 3x3 by Cramers rule
342
Vector3r SolveLinSys3x3(Matrix3r A, Vector3r y){
343
//only system 3x3 by Cramers rule
344
double det = A(0,0)*A(1,1)*A(2,2)+A(0,1)*A(1,2)*A(2,0)+A(0,2)*A(1,0)*A(2,1)-A(0,2)*A(1,1)*A(2,0)-A(0,1)*A(1,0)*A(2,2)-A(0,0)*A(1,2)*A(2,1);
345
if (det == 0) {cerr << "error in linear solver" << endl; return Vector3r(0,0,0);}
346
return Vector3r((y(0)*A(1,1)*A(2,2)+A(0,1)*A(1,2)*y(2)+A(0,2)*y(1)*A(2,1)-A(0,2)*A(1,1)*y(2)-A(0,1)*y(1)*A(2,2)-y(0)*A(1,2)*A(2,1))/det, (A(0,0)*y(1)*A(2,2)+y(0)*A(1,2)*A(2,0)+A(0,2)*A(1,0)*y(2)-A(0,2)*y(1)*A(2,0)-y(0)*A(1,0)*A(2,2)-A(0,0)*A(1,2)*y(2))/det, (A(0,0)*A(1,1)*y(2)+A(0,1)*y(1)*A(2,0)+y(0)*A(1,0)*A(2,1)-y(0)*A(1,1)*A(2,0)-A(0,1)*A(1,0)*y(2)-A(0,0)*y(1)*A(2,1))/det);
349
//**********************************************************************************
350
/*return convex hull of points
351
critical point, because CGAL often returnes segmentation fault. The planes must be sufficiently "different". This is, however, checked elswhere by DISTANCE_LIMIT variable.
353
Polyhedron ConvexHull(vector<CGALpoint> &planes){
355
//cout << "C"; cout.flush();
356
if (planes.size()>3) CGAL::convex_hull_3(planes.begin(), planes.end(), Int);
357
//cout << "-C"<< endl; cout.flush();
361
//**********************************************************************************
362
//determination of normal direction of intersection
364
Vector3r FindNormal(Polyhedron Int, Polyhedron PA, Polyhedron PB){
366
//determine which plane is from which polyhedra
367
Polyhedron::Plane_iterator pi, pj;
368
std::transform( Int.facets_begin(), Int.facets_end(), Int.planes_begin(),Plane_equation());
369
std::transform( PA.facets_begin(), PA.facets_end(), PA.planes_begin(),Plane_equation());
370
std::transform( PB.facets_begin(), PB.facets_end(), PB.planes_begin(),Plane_equation());
371
vector<bool> from_A(Int.size_of_facets());
372
vector<double> minsA(Int.size_of_facets());
373
vector<double> minsB(Int.size_of_facets());
375
double minA, minB, k;
376
for(pi = Int.planes_begin(); pi!=Int.planes_end(); ++pi,i++){
379
for(pj=PA.planes_begin(); pj!=PA.planes_end(); ++pj){
380
k = PlaneDifference(*pi, *pj);
384
if (minA<FIND_NORMAL_LIMIT) {from_A[i] = true; break;} //already satisfactory
388
if (minA<FIND_NORMAL_LIMIT) continue;
389
for(pj=PB.planes_begin(); pj!=PB.planes_end(); ++pj){
390
k = PlaneDifference(*pi, *pj);
395
if (minB<FIND_NORMAL_LIMIT || minB<minA) break; //already satisfactory
398
from_A[i] = ((minA < minB) ? true : false);
400
//check that not all belongs to A and not all belongs to B
401
if (*std::min_element(from_A.begin(),from_A.end())==1){
402
int loc = std::min_element(minsB.begin(),minsB.end()) - minsB.begin();
404
}else if (*std::max_element(from_A.begin(),from_A.end())==0){
405
int loc = std::min_element(minsA.begin(),minsA.end()) - minsA.begin();
409
//find intersecting segments
410
vector<Segment> segments;
413
for (Polyhedron::Edge_iterator hei = Int.edges_begin(); hei!=Int.edges_end(); ++hei){
414
a = std::distance(Int.facets_begin(), hei->facet());
415
b = std::distance(Int.facets_begin(), hei->opposite()->facet());
416
if ((from_A[a] && !from_A[b]) || (from_A[b] && !from_A[a])) segments.push_back(Segment(hei->vertex()->point(),hei->opposite()->vertex()->point()));
419
//find normal direction
421
linear_least_squares_fitting_3(segments.begin(),segments.end(),fit,CGAL::Dimension_tag<1>());
422
CGALvector CGALnormal=fit.orthogonal_vector();
423
CGALnormal = CGALnormal/sqrt(CGALnormal.squared_length());
424
// reverse direction if projection of the (contact_point-centroid_of_B) vector onto the normal is negative (i.e. the normal points more towards B)
426
return FromCGALVector(CGALnormal);
429
//**********************************************************************************
431
double CalculateProjectionArea(Polyhedron Int, CGALvector CGALnormal){
432
//calculate area of projection of Intersection into the normal plane
435
Polyhedron::Halfedge_around_facet_circulator hfc0;
438
std::transform( Int.facets_begin(), Int.facets_end(), Int.planes_begin(),Plane_equation());
439
for(Polyhedron::Facet_iterator fi = Int.facets_begin(); fi!= Int.facets_end(); ++fi){
440
assert(fi->is_triangle());
441
hfc0 = fi->facet_begin();
442
normal2 = fi->plane().orthogonal_vector();
443
norm2 = normal2.squared_length();
444
if(norm2 < 1E-20) continue;
445
abs_size = 0.5*sqrt((cross_product(CGALvector(hfc0->vertex()->point(),hfc0->next()->vertex()->point()),CGALvector(hfc0->vertex()->point(),hfc0->next()->next()->vertex()->point()))).squared_length());
446
// factor 0.5 because this procedure returnes doubles projected area
447
if (abs_size>0) area += 0.5*abs_size*abs(CGALnormal*normal2/sqrt(norm2));
452
//**********************************************************************************
453
//prepare data for CGAL convex hull
454
vector<Plane> MergePlanes(vector<Plane> planes1, vector<Plane> planes2, double limit){
455
vector<Plane> P = planes1;
457
for(vector<Plane>::iterator i = planes2.begin(); i!=planes2.end(); ++i){
459
for(vector<Plane>::iterator j = planes1.begin(); j!=planes1.end(); ++j){
460
if (PlaneDifference(*i,*j) < limit){
465
if (add) P.push_back(*i);
470
//**********************************************************************************
471
//returnes intersecting polyhedron of polyhedron & plane (possibly empty)
472
Polyhedron Polyhedron_Plane_intersection(Polyhedron A, Plane B, CGALpoint centroid, CGALpoint X){
474
Polyhedron Intersection;
476
vector<Plane> planes1, planes2;
477
vector<CGALpoint> dual_planes;
478
// test if do intersect, find some intersecting point
479
bool intersection_found = false;
480
double lim = pow(DISTANCE_LIMIT,2);
481
// test centroid of previous intersection
482
if(Is_inside_Polyhedron(A,X,DISTANCE_LIMIT) && Oriented_squared_distance(B,X)<=-lim) {
483
intersection_found = true;
485
// find new point by checking polyhedron vertices that lies on negative side of the plane
487
for(Polyhedron::Vertex_iterator vIter = A.vertices_begin(); vIter != A.vertices_end() && !intersection_found ; vIter++){
488
if(Oriented_squared_distance(B,vIter->point())<=-lim) {
489
intersection_found = true;
490
CGAL::Object result = CGAL::intersection(Line(vIter->point(),centroid), B);
491
if (const CGALpoint *ipoint = CGAL::object_cast<CGALpoint>(&result)) {
492
inside = vIter->point() + 0.5*CGALvector(vIter->point(),*ipoint);
494
cerr << "Error in line-plane intersection" << endl;
499
//no intersectiong point => no intersection polyhedron
500
if(!intersection_found) return Intersection;
503
//set the intersection point to origin
504
Transformation transl_back(CGAL::TRANSLATION, inside - CGALpoint(0.,0.,0.));
505
Transformation transl(CGAL::TRANSLATION, CGALpoint(0.,0.,0.)-inside);
507
std::transform( A.points_begin(), A.points_end(), A.points_begin(), transl);
508
B = transl.transform(B);
511
planes1.push_back(B);
514
std::transform( A.facets_begin(), A.facets_end(), A.planes_begin(),Plane_equation());
515
for(Polyhedron::Plane_iterator pi =A.planes_begin(); pi!=A.planes_end(); ++pi) planes2.push_back(*pi);;
518
planes1 = MergePlanes(planes1,planes2, MERGE_PLANES_LIMIT);//MERGE_PLANES_LIMIT);
519
for(vector<Plane>::iterator pi =planes1.begin(); pi!= planes1.end(); ++pi) dual_planes.push_back(CGALpoint(-pi->a()/pi->d(),-pi->b()/pi->d(),-pi->c()/pi->d()));
521
//compute convex hull of it
522
Intersection = ConvexHull(dual_planes);
523
if (Intersection.empty()) {cout << "0" << endl; cout.flush(); return Intersection;}
526
std::transform( Intersection.facets_begin(), Intersection.facets_end(), Intersection.planes_begin(),Plane_equation());
527
Intersection = Simplify(Intersection, SIMPLIFY_LIMIT);
528
std::transform( Intersection.facets_begin(), Intersection.facets_end(), Intersection.planes_begin(),Plane_equation());
532
for(Polyhedron::Plane_iterator pi =Intersection.planes_begin(); pi!=Intersection.planes_end(); ++pi) dual_planes.push_back(CGALpoint(-pi->a()/pi->d(),-pi->b()/pi->d(),-pi->c()/pi->d()));
534
//compute convex hull of it
535
Intersection = ConvexHull(dual_planes);
537
//return to original position
538
std::transform( Intersection.points_begin(), Intersection.points_end(), Intersection.points_begin(), transl_back);
540
if (Intersection.size_of_facets() < 4) Intersection.clear();
544
//**********************************************************************************
545
//returnes intersecting polyhedron of polyhedron & plane defined by diriction and point
546
Polyhedron Polyhedron_Plane_intersection(Polyhedron A, Vector3r direction, Vector3r plane_point){
547
Plane B(ToCGALPoint(plane_point), ToCGALVector(direction));
548
CGALpoint X = ToCGALPoint(plane_point) - 1E-8*ToCGALVector(direction);
549
return Polyhedron_Plane_intersection(A, B, ToCGALPoint(plane_point), X);
552
//**********************************************************************************
553
//returnes intersecting polyhedron of two polyhedrons (possibly empty)
554
Polyhedron Polyhedron_Polyhedron_intersection(Polyhedron A, Polyhedron B, CGALpoint X, CGALpoint centroidA, CGALpoint centroidB, std::vector<int> &sep_plane){
556
Polyhedron Intersection;
558
vector<Plane> planes1, planes2;
559
vector<CGALpoint> dual_planes;
560
Polyhedron::Plane_iterator pi;
561
CGALpoint inside(0,0,0);
563
bool intersection_found = false;
564
std::transform( A.facets_begin(), A.facets_end(), A.planes_begin(),Plane_equation());
565
std::transform( B.facets_begin(), B.facets_end(), B.planes_begin(),Plane_equation());
568
// test that X is really inside
569
if(Is_inside_Polyhedron(A,X,DISTANCE_LIMIT) && Is_inside_Polyhedron(B,X,DISTANCE_LIMIT)) {
570
intersection_found = true;
573
if (!do_intersect(A, B, sep_plane)) return Intersection;
574
//some intersection point
575
double dist_S, dist_T;
576
double lim2 = pow(DISTANCE_LIMIT,2);
578
double factor = sqrt(DISTANCE_LIMIT * 1.5);
579
//test vertices A - not needed, edges are enough
580
for (Polyhedron::Vertex_iterator vIter = A.vertices_begin(); vIter != A.vertices_end() && !intersection_found; vIter++){
581
d1 = centroidA-vIter->point();
582
inside = vIter->point() + d1/sqrt(d1.squared_length())*DISTANCE_LIMIT*20.;
583
intersection_found = (Is_inside_Polyhedron(A,inside,DISTANCE_LIMIT) && Is_inside_Polyhedron(B,inside,DISTANCE_LIMIT));
585
//test vertices B - necessary
586
for (Polyhedron::Vertex_iterator vIter = B.vertices_begin(); vIter != B.vertices_end() && !intersection_found; vIter++){
587
d1 = centroidB-vIter->point();
588
inside = vIter->point() + d1/sqrt(d1.squared_length())*DISTANCE_LIMIT*20.;
589
intersection_found = (Is_inside_Polyhedron(A,inside,DISTANCE_LIMIT) && Is_inside_Polyhedron(B,inside,DISTANCE_LIMIT));
593
for (Polyhedron::Edge_iterator eIter = A.edges_begin(); eIter != A.edges_end() && !intersection_found; eIter++){
594
for (Polyhedron::Facet_iterator fIter = B.facets_begin(); fIter != B.facets_end() && !intersection_found; fIter++){
595
dist_S = Oriented_squared_distance(fIter->plane(), eIter->vertex()->point());
596
dist_T = Oriented_squared_distance(fIter->plane(), eIter->opposite()->vertex()->point());
597
if (dist_S*dist_T >= 0 || abs(dist_S)<lim2 || abs(dist_T)<lim2) continue;
598
inside = eIter->vertex()->point() + (eIter->opposite()->vertex()->point()-eIter->vertex()->point())*sqrt(abs(dist_S))/(sqrt(abs(dist_S))+sqrt(abs(dist_T)));
599
// the fact that edge intersects the facet (not only its plane) is not explicitely checked, it sufices to check that the resulting point is inside both polyhedras
600
Plane p1 = fIter->plane();
601
Plane p2 = eIter->facet()->plane();
602
Plane p3 = eIter->opposite()->facet()->plane();
603
Amatrix << p1.a(),p1.b(),p1.c(),
604
p2.a(),p2.b(),p2.c(),
605
p3.a(),p3.b(),p3.c();
606
y = Vector3r(-p1.d()-factor*sqrt(pow(p1.a(),2)+pow(p1.b(),2)+pow(p1.c(),2)),-p2.d()-factor*sqrt(pow(p2.a(),2)+pow(p2.b(),2)+pow(p2.c(),2)),-p3.d()-factor*sqrt(pow(p3.a(),2)+pow(p3.b(),2)+pow(p3.c(),2)));
607
inside = ToCGALPoint(SolveLinSys3x3(Amatrix,y));
608
intersection_found = (Is_inside_Polyhedron(A,inside,DISTANCE_LIMIT) && Is_inside_Polyhedron (B,inside,DISTANCE_LIMIT));
613
//Polyhedrons do not intersect
614
if (!intersection_found) return Intersection;
616
//set the intersection point to origin
617
Transformation transl_back(CGAL::TRANSLATION, inside - CGALpoint(0.,0.,0.));
618
Transformation transl(CGAL::TRANSLATION, CGALpoint(0.,0.,0.)-inside);
620
std::transform( A.points_begin(), A.points_end(), A.points_begin(), transl);
621
std::transform( B.points_begin(), B.points_end(), B.points_begin(), transl);
623
//dualize polyhedrons
624
std::transform( A.facets_begin(), A.facets_end(), A.planes_begin(),Plane_equation());
625
std::transform( B.facets_begin(), B.facets_end(), B.planes_begin(),Plane_equation());
626
for(Polyhedron::Plane_iterator pi =A.planes_begin(); pi!=A.planes_end(); ++pi) planes1.push_back(*pi);
627
for(Polyhedron::Plane_iterator pi =B.planes_begin(); pi!=B.planes_end(); ++pi) planes2.push_back(*pi);
631
planes1 = MergePlanes(planes1,planes2, MERGE_PLANES_LIMIT);//MERGE_PLANES_LIMIT);
632
for(vector<Plane>::iterator pi =planes1.begin(); pi!= planes1.end(); ++pi) dual_planes.push_back(CGALpoint(-pi->a()/pi->d(),-pi->b()/pi->d(),-pi->c()/pi->d()));
634
//compute convex hull of it
635
Intersection = ConvexHull(dual_planes);
636
if (Intersection.empty()) {cout << "0" << endl; cout.flush(); return Intersection;};
639
std::transform( Intersection.facets_begin(), Intersection.facets_end(), Intersection.planes_begin(),Plane_equation());
640
Intersection = Simplify(Intersection, SIMPLIFY_LIMIT);
641
std::transform( Intersection.facets_begin(), Intersection.facets_end(), Intersection.planes_begin(),Plane_equation());
645
for(Polyhedron::Plane_iterator pi =Intersection.planes_begin(); pi!=Intersection.planes_end(); ++pi) dual_planes.push_back(CGALpoint(-pi->a()/pi->d(),-pi->b()/pi->d(),-pi->c()/pi->d()));
647
//compute convex hull of it
648
Intersection = ConvexHull(dual_planes);
649
//return to original position
650
std::transform( Intersection.points_begin(), Intersection.points_end(), Intersection.points_begin(), transl_back);
652
if (Intersection.size_of_facets() < 4) Intersection.clear();
656
//**********************************************************************************
658
//returnes intersection of Sphere and polyhedron (possibly empty) - not finished
659
bool Sphere_Polyhedron_intersection(Polyhedron A, double r, CGALpoint C, CGALpoint centroid, double volume, CGALvector normal, double area){
663
double r2 = pow(r,2);
665
Polyhedron::Vertex_iterator closest_vert;
667
double min_dist2 = (C-centroid).squared_length();
669
for(Polyhedron::Vertex_iterator vi=A.vertices_begin(); vi!=A.vertices_end(); ++vi){
670
dist2 = (C-vi->point()).squared_length();
671
if(min_dist2 > dist2) {min_dist2 = dist2; closest_vert=vi;}
673
if(min_dist2 < r2){ //test if we are already inside the sphere
679
CGALvector v1(C-closest_vert->point());
680
v1 = v1/sqrt(v1.squared_length());
681
Polyhedron::Halfedge_around_vertex_circulator closest_edge;
684
double max_cos_angle=-1;
686
for(Polyhedron::Halfedge_around_vertex_circulator hfi=closest_vert->vertex_begin(); i<(int)closest_vert->degree(); ++hfi, i++){
687
v2 = hfi->opposite()->vertex()->point()-closest_vert->point();
688
v2 = v2/sqrt(v2.squared_length());
690
if(cos_angle > max_cos_angle) closest_edge=hfi; max_cos_angle=cos_angle; //find the edge with minimum angle
692
if(max_cos_angle<=0) return false; //all edges goes with angle above or equal 90
693
double k = (C - closest_vert->point())*v2; //find closest point on the most descending edge (it must be on edge, otherwise opposite point would be already closer)
694
CGALpoint closest_point = closest_vert->point() + k*v2;
695
if((C-closest_point).squared_length()<r2){ //test if we are already inside the sphere
702
v1 = (C-closest_point);
703
v1 = v1/sqrt(v1.squared_length());
704
v2 = closest_edge->vertex()->point()-closest_edge->opposite()->vertex()->point();
705
CGALvector v3 = closest_edge->facet()->plane().orthogonal_vector();
706
CGALvector v4 = closest_edge->opposite()->facet()->plane().orthogonal_vector();
707
v3 = CGAL::cross_product(v3,v2);
708
v4 = CGAL::cross_product(v4,v2*(-1));
710
if (v1*v3>=0 && v1*v4>=0) return false; // both planes running away
711
if (v1*v3<0) closest_plane = closest_edge->facet()->plane();
712
else closest_plane = closest_edge->opposite()->facet()->plane();
713
closest_point = closest_plane.projection(C);
714
if((C-closest_point).squared_length()<r2){ //test if we are already inside the sphere
715
double h = sqrt((C-closest_point).squared_length());
716
volume = 3.1415*pow(h,2)/3*(3*r-h);
724
//**********************************************************************************
725
Vector3r FromCGALPoint(CGALpoint A){
726
return Vector3r(A.x(), A.y(), A.z());
729
//**********************************************************************************
730
Vector3r FromCGALVector(CGALvector A){
731
return Vector3r(A.x(), A.y(), A.z());
734
//**********************************************************************************
735
CGALpoint ToCGALPoint(Vector3r A){
736
return CGALpoint(A[0], A[1], A[2]);
739
//**********************************************************************************
740
CGALvector ToCGALVector(Vector3r A){
741
return CGALvector(A[0], A[1], A[2]);
744
//**********************************************************************************
746
shared_ptr<Body> NewPolyhedra(vector<Vector3r> v, shared_ptr<Material> mat){
747
shared_ptr<Body> body(new Body);
749
body->shape=shared_ptr<Polyhedra>(new Polyhedra());
750
Polyhedra* A = static_cast<Polyhedra*>(body->shape.get());
753
body->state->pos= A->GetCentroid();
754
body->state->mass=body->material->density*A->GetVolume();
755
body->state->inertia =A->GetInertia()*body->material->density;
756
body->state->ori = A->GetOri();
757
body->bound=shared_ptr<Aabb>(new Aabb);
758
body->setAspherical(true);
763
//**********************************************************************************
765
void SplitPolyhedra(const shared_ptr<Body>& body, Vector3r direction){
767
const Se3r& se3=body->state->se3;
768
Polyhedra* A = static_cast<Polyhedra*>(body->shape.get());
769
State* X = static_cast<State*>(body->state.get());
771
Vector3r OrigPos = X->pos;
772
Vector3r OrigVel = X->vel;
773
Vector3r OrigAngVel = X->angVel;
775
//move and rotate CGAL structure Polyhedron
776
Matrix3r rot_mat = (se3.orientation).toRotationMatrix();
777
Vector3r trans_vec = se3.position;
778
Transformation t_rot_trans(rot_mat(0,0),rot_mat(0,1),rot_mat(0,2), trans_vec[0],rot_mat(1,0),rot_mat(1,1),rot_mat(1,2),trans_vec[1],rot_mat(2,0),rot_mat(2,1),rot_mat(2,2),trans_vec[2],1.);
779
Polyhedron PA = A->GetPolyhedron();
780
std::transform( PA.points_begin(), PA.points_end(), PA.points_begin(), t_rot_trans);
782
//calculate splitted polyhedrons
783
Polyhedron S1 = Polyhedron_Plane_intersection(PA, direction, trans_vec);
784
Polyhedron S2 = Polyhedron_Plane_intersection(PA, (-1)*direction, trans_vec);
787
//replace original polyhedron
789
for(Polyhedron::Vertex_iterator vi = S1.vertices_begin(); vi != S1.vertices_end(); vi++){ A->v.push_back(FromCGALPoint(vi->point()));};
791
X->pos = A->GetCentroid();
792
X->ori = A->GetOri();
793
X->mass=body->material->density*A->GetVolume();
794
X->refPos[0] = X->refPos[0]+1.;
795
X->inertia =A->GetInertia()*body->material->density;
799
for(Polyhedron::Vertex_iterator vi = S2.vertices_begin(); vi != S2.vertices_end(); vi++){ v2.push_back(FromCGALPoint(vi->point()));};
800
shared_ptr<Body> BP = NewPolyhedra(v2, body->material);
801
//BP->shape->color = body->shape->color;
802
BP->shape->color = Vector3r(double(rand())/RAND_MAX,double(rand())/RAND_MAX,double(rand())/RAND_MAX);
805
Scene* scene=Omega::instance().getScene().get();
806
//scene->bodies->erase(body->id);
807
scene->bodies->insert(BP);
809
//set proper state variables
810
X->vel = OrigVel + OrigAngVel.cross(X->pos-OrigPos);
811
BP->state->vel = OrigVel + OrigAngVel.cross(BP->state->pos-OrigPos);
812
X->angVel = OrigAngVel;
813
BP->state->angVel = OrigAngVel;