source: trunk/source/graphics_reps/src/BooleanProcessor.src @ 1202

Last change on this file since 1202 was 1140, checked in by garnier, 15 years ago

update to CVS

File size: 77.1 KB
Line 
1/***********************************************************************
2 *                                                                     *
3 * Name: BooleanProcessor                            Date:    10.12.99 *
4 * Author: E.Chernyaev                               Revised:          *
5 *                                                                     *
6 * Function: Internal class for executing boolean operations           *
7 *           on Polyhedra                                              *
8 *                                                                     *
9 ***********************************************************************/
10
11//G.Barrand : begin
12#define BP_GEANT4
13
14#ifdef BP_GEANT4 //G.Barrand
15
16#include <CLHEP/Geometry/Plane3D.h>
17#include <CLHEP/Geometry/Plane3D.h>
18typedef HepGeom::Plane3D<double> HVPlane3D;
19typedef HepGeom::Point3D<double> HVPoint3D;
20typedef HepGeom::Normal3D<double> HVNormal3D;
21
22#else //BP_HEPVIS
23
24#define ExtNode          HEPVis_ExtNode
25#define ExtEdge          HEPVis_ExtEdge
26#define ExtFace          HEPVis_ExtFace
27#define FaceList         HEPVis_FaceList
28#define ExtPolyhedron    HEPVis_ExtPolyhedron
29#define BooleanProcessor HEPVis_BooleanProcessor
30
31#define HepPolyhedron SbPolyhedron
32#define G4Facet SbFacet
33
34#include <HEPVis/SbPlane.h>
35typedef HEPVis::SbPlane HVPlane3D;
36
37#endif
38
39//using namespace HepGeom;
40
41//#define BP_DEBUG
42
43//G.Barrand : end
44
45#define INITIAL_SIZE 200
46#define CRAZY_POINT  HVPoint3D(-10.e+6, -10.e+6, -10.e+6)
47//#define GRANULARITY  10.e+5;
48#define GRANULARITY  10.e+5  //G.Barrand : rm the trailing ;
49
50#define SWAP(A,B) w = A; A = B; B = w
51
52#define OP_UNION         0    // Operations
53#define OP_INTERSECTION  1
54#define OP_SUBTRACTION   2
55
56#define OUT_OF_PLANE     0    // Face vs face statuses
57#define ON_PLANE         1
58#define INTERSECTION     2
59#define EDGE             3
60#define NON_PLANAR_FACE  4
61
62#define UNKNOWN_FACE     0    // Face statuses
63#define ORIGINAL_FACE   -1
64#define NEW_FACE        -2
65#define UNSUITABLE_FACE -3
66#define DEFECTIVE_FACE  -4
67
68// -------------------------------------------- Simplified STL vector ---
69//G.Barrand : begin
70#include <vector>
71using namespace std;
72/*
73template<class T>
74class vector {
75 private:
76  int cur_size, max_size;
77  T * v;
78
79 public:
80  vector(): cur_size(0), max_size(INITIAL_SIZE), v(new T[INITIAL_SIZE]) {}
81  ~vector() { delete [] v; } 
82
83  void      clear()                 { cur_size = 0; }
84  int       size()            const { return cur_size; }
85  T &       operator[](int i)       { return v[i]; }
86  const T & operator[](int i) const { return v[i]; }
87  T &       front()                 { return v[0]; }
88  const T & front()           const { return v[0]; }
89  T &       back()                  { return v[cur_size-1]; }
90  const T & back()            const { return v[cur_size-1]; }
91  void      pop_back()              { cur_size--; }
92  void      push_back(const T & a) {
93    if (cur_size == max_size) {
94      T * w     = v;
95      max_size *= 2;
96      v         = new T[max_size];
97      for (int i=0; i<cur_size; i++) v[i] = w[i];
98      v[cur_size++] = a;
99      delete [] w;
100    }else{
101      v[cur_size++] = a;
102    }
103  }
104};
105*/
106//G.Barrand : end
107
108// ---------------------------------------------------- Extended node ---
109class ExtNode {
110 public:
111  HVPoint3D v;
112  int        s;
113
114 public:
115  ExtNode(HVPoint3D vertex=HVPoint3D(), int status=0)
116    : v(vertex), s(status) {}
117  ~ExtNode() {}
118
119  ExtNode(const ExtNode & node) : v(node.v), s(node.s) {}
120
121  ExtNode & operator=(const ExtNode & node) {
122    v = node.v;
123    s = node.s;
124    return *this;
125  }
126};
127
128// ---------------------------------------------------- Extended edge ---
129class ExtEdge {
130 public:
131  int       i1, i2;           // end points
132  int       iface1;           // native face
133  int       iface2;           // neighbouring face
134  int       ivis;             // visibility: +1 (visible), -1 (invisible)
135  int       inext;            // index of next edge
136
137 public:
138  ExtEdge(int k1=0, int k2=0, int kface1=0, int kface2=0, int kvis=0) :
139    i1(k1), i2(k2), iface1(kface1), iface2(kface2), ivis(kvis), inext(0) {}
140
141  ~ExtEdge() {};
142
143  ExtEdge(const ExtEdge & edge) :
144    i1(edge.i1), i2(edge.i2), iface1(edge.iface1), iface2(edge.iface2),
145    ivis(edge.ivis), inext(edge.inext) {}
146
147  ExtEdge & operator=(const ExtEdge & edge) {
148    i1     = edge.i1;
149    i2     = edge.i2;
150    iface1 = edge.iface1;
151    iface2 = edge.iface2;
152    ivis   = edge.ivis;
153    inext  = edge.inext;
154    return *this;
155  }
156
157  void invert() {
158    int w;
159    SWAP(i1, i2);
160  }
161};
162
163// ---------------------------------------------------- Extended face ---
164class ExtFace {
165 private:
166  std::vector<ExtEdge>& edges; //G.Barrand
167 public:
168  int        iedges[4];        // indices of original edges
169  HVPlane3D plane;            // face plane
170  double     rmin[3], rmax[3]; // bounding box
171  int        iold;             // head of the list of the original edges
172  int        inew;             // head of the list of the new edges
173  int        iprev;            // index of previous face
174  int        inext;            // index of next face
175
176 public:
177  //G.Barrand : ExtFace(int iedge=0) : iold(iedge), inew(0), iprev(iprev), inext(0) {}
178  ExtFace(std::vector<ExtEdge>& a_edges,int iedge)
179  : edges(a_edges), iold(iedge), inew(0), iprev(0), inext(0) {
180    //G.Barrand : initialize arrays to quiet valgrind.
181   {for (int i=0; i<4; i++) { iedges[i] = 0; }}
182   {for (int i=0; i<3; i++) { rmin[i] = 0; rmax[i] = 0; }}
183  }
184  ~ExtFace() {}
185
186  ExtFace(const ExtFace & face) :
187    edges(face.edges), //G.Barrand
188    plane(face.plane), iold(face.iold), inew(face.inew),
189    iprev(face.iprev), inext(face.inext)
190  {
191    int i;
192    for (i=0; i<4; i++) { iedges[i] = face.iedges[i]; }
193    for (i=0; i<3; i++) { rmin[i] = face.rmin[i]; rmax[i] = face.rmax[i]; }
194  }
195
196  ExtFace & operator=(const ExtFace & face) {
197    //FIXME : edges(face.edges) ???? //G.Barrand
198    int i;
199    for (i=0; i<4; i++) { iedges[i] = face.iedges[i]; }
200    plane  = face.plane;
201    for (i=0; i<3; i++) { rmin[i] = face.rmin[i]; rmax[i] = face.rmax[i]; }
202    iold   = face.iold;
203    inew   = face.inew;
204    iprev  = face.iprev;
205    inext  = face.inext;
206    return *this;
207  }
208
209  void invert();
210};
211
212// ---------------------------------------------------- Global arrays ---
213//G.Barrand : MacIntel : crash with g++-4.0.1 with -O on some subtract.
214//            Anyway static of objects is proved to be not safe.
215//            We put the below vector as members of BooleanProcessor.
216//GB static std::vector<ExtNode> nodes;        // vector of nodes
217//GB static std::vector<ExtEdge> edges;        // vector of edges
218//GB static std::vector<ExtFace> faces;        // vector of faces
219
220// ---------------------------------------------------- List of faces ---
221class FaceList {
222 private:
223  std::vector<ExtFace>& faces; //G.Barrad : end
224 private:
225  int ihead;
226  int ilast;
227
228 public:
229  //G.Barrand : FaceList() : ihead(0), ilast(0) {}
230  FaceList(std::vector<ExtFace>& a_faces) : faces(a_faces),ihead(0),ilast(0) {}
231  ~FaceList() {}
232
233  void clean() { ihead = 0; ilast = 0; } 
234  int front()  { return ihead; }
235
236  void push_back(int i) {
237    if (ilast == 0) { ihead = i; } else { faces[ilast].inext = i; }
238    ExtFace& face = faces[i]; //G.Barrand : optimize.
239    face.iprev = ilast;
240    face.inext = 0;
241    ilast = i;
242  }
243
244  void remove(int i) {
245    ExtFace& face = faces[i]; //G.Barrand : optimize.
246    if (ihead == i) {
247      ihead = face.inext;
248    }else{
249      faces[face.iprev].inext = face.inext;
250    }
251    if (ilast == i) {
252      ilast = face.iprev;
253    }else{
254      faces[face.inext].iprev = face.iprev;
255    }
256    face.iprev = 0;
257    face.inext = 0;
258  }
259};
260
261// --------------------- Polyhedron with extended access to
262//                       its members from the BooleanProcessor class ---
263class ExtPolyhedron : public HepPolyhedron {
264  friend class BooleanProcessor;
265  virtual HepPolyhedron& operator = (const HepPolyhedron& from) {
266    return HepPolyhedron::operator = (from);
267  }
268};
269
270// ----------------------------------------- Boolean processor class ---
271class BooleanProcessor {
272 private:
273  static int ishift; //G.Barrand
274  std::vector<ExtNode> nodes;        // vector of nodes //G.Barrand
275  std::vector<ExtEdge> edges;        // vector of edges //G.Barrand
276  std::vector<ExtFace> faces;        // vector of faces //G.Barrand
277 private:
278  int             processor_error;   // is set in case of error
279  int             operation;  // 0 (union), 1 (intersection), 2 (subtraction)
280  int             ifaces1, ifaces2;  // lists of faces
281  int             iout1,   iout2;    // lists of faces with status "out"
282  int             iunk1,   iunk2;    // lists of faces with status "unknown"
283  double          rmin[3], rmax[3];  // intersection of bounding boxes
284  double          del;               // precision (tolerance)   
285
286  FaceList        result_faces;      // list of accepted faces
287  FaceList        suitable_faces;    // list of suitable faces
288  FaceList        unsuitable_faces;  // list of unsuitable faces
289  FaceList        unknown_faces;     // list of unknown faces
290
291  vector<int>     external_contours; // heads of external contours
292  vector<int>     internal_contours; // heads of internal contours
293
294 private:
295  void   takePolyhedron(const HepPolyhedron & p, double, double, double);
296  double findMinMax();
297  void   selectOutsideFaces(int & ifaces, int & iout);
298  int    testFaceVsPlane(ExtEdge & edge);
299  void   renumberNodes(int & i1, int & i2, int & i3, int & i4);
300  int    testEdgeVsEdge(ExtEdge & edge1, ExtEdge & edge2);
301  void   removeJunkNodes() { while(nodes.back().s != 0) nodes.pop_back(); }
302  void   divideEdge(int & i1, int & i2);
303  void   insertEdge(const ExtEdge & edge);
304  void   caseII(ExtEdge & edge1, ExtEdge & edge2);
305  void   caseIE(ExtEdge & edge1, ExtEdge & edge2);
306  void   caseEE(ExtEdge & edge1, ExtEdge & edge2);
307  void   testFaceVsFace(int iface1, int iface2);
308  void   invertNewEdges(int iface);
309  void   checkDoubleEdges(int iface);
310  void   assembleFace(int what, int iface);
311  void   assembleNewFaces(int what, int ihead);
312  void   initiateLists();
313  void   assemblePolyhedra();
314  void   findABC(double x1, double y1, double x2, double y2,
315                 double &a, double &b, double &c) const;
316  int    checkDirection(double *x, double *y) const;
317  int    checkIntersection(int ix, int iy, int i1, int i2) const;
318  void   mergeContours(int ix, int iy, int kext, int kint);
319  int    checkTriangle(int iedge1, int iedge2, int ix, int iy) const;
320  void   triangulateContour(int ix, int iy, int ihead);
321  void   modifyReference(int iface, int i1, int i2, int iref);
322  void   triangulateFace(int iface);
323  HepPolyhedron createPolyhedron();
324
325 public:
326  //G.Barrand : BooleanProcessor() {}
327  BooleanProcessor() //G.Barrand
328  :result_faces(faces)
329  ,suitable_faces(faces)
330  ,unsuitable_faces(faces)
331  ,unknown_faces(faces)
332  {
333  }
334
335  ~BooleanProcessor() {}
336
337  HepPolyhedron execute(int op,
338                        const HepPolyhedron &a,
339                        const HepPolyhedron &b,
340                        int& err);
341
342  void draw();
343  void draw_edge(int, int);
344  void draw_contour(int, int, int);
345  void draw_faces(int, int, int);
346  void print_face(int);
347  void print_edge(int);
348  int get_processor_error() const {return processor_error;}
349
350  void dump(); //G.Barrand
351  static int get_shift(); //G.Barrand
352  static void set_shift(int); //G.Barrand
353  static int get_num_shift(); //G.Barrand
354};
355
356inline void ExtFace::invert()
357/***********************************************************************
358 *                                                                     *
359 * Name: ExtFace::invert()                           Date:    28.02.00 *
360 * Author: E.Chernyaev                               Revised:          *
361 *                                                                     *
362 * Function: Invert face                                               *
363 *                                                                     *
364 ***********************************************************************/
365{
366  int iEprev, iEcur, iEnext;
367
368  iEprev = 0; iEcur = iold;
369  while (iEcur > 0) {
370    ExtEdge& edge = edges[iEcur]; //G.Barrand : optimize.
371    edge.invert();
372    iEnext = edge.inext;
373    edge.inext = iEprev;
374    iEprev = iEcur;
375    iEcur  = iEnext;
376  }
377  if (iold > 0) iold = iEprev;
378
379  iEprev = 0; iEcur = inew;
380  while (iEcur > 0) {
381    ExtEdge& edge = edges[iEcur]; //G.Barrand : optimize.
382    edge.invert();
383    iEnext = edge.inext;
384    edge.inext = iEprev;
385    iEprev = iEcur;
386    iEcur  = iEnext;
387  }
388  if (inew > 0) inew = iEprev;
389
390#ifdef BP_GEANT4 //G.Barrand
391  plane = HVPlane3D(-plane.a(), -plane.b(), -plane.c(), -plane.d());
392#else
393  plane = HVPlane3D(-plane.getNormal(), -plane.getDistanceFromOrigin());
394#endif
395}
396
397void BooleanProcessor::takePolyhedron(const HepPolyhedron & p,
398                                      double dx, double dy, double dz)
399/***********************************************************************
400 *                                                                     *
401 * Name: BooleanProcessor::takePolyhedron            Date:    16.12.99 *
402 * Author: E.Chernyaev                               Revised:          *
403 *                                                                     *
404 * Function: Transfer Polyhedron to internal representation            *
405 *                                                                     *
406 ***********************************************************************/
407{
408  int i, k, nnode, iNodes[5], iVis[4], iFaces[4];
409  int dnode = nodes.size() - 1;
410  int dface = faces.size() - 1;
411
412  //   S E T   N O D E S
413
414  //  for (i=1; i <= p.GetNoVertices(); i++) { 
415  //    nodes.push_back(ExtNode(p.GetVertex(i)));
416  //  }
417
418  HVPoint3D ppp;       
419  for (i=1; i <= p.GetNoVertices(); i++) { 
420#ifdef BP_GEANT4 //G.Barrand
421    ppp = p.GetVertex(i);
422    ppp.setX(ppp.x()+dx);
423    ppp.setY(ppp.y()+dy);
424    ppp.setZ(ppp.z()+dz);
425#else
426    ppp = p.GetVertexFast(i);
427    ppp += HVPoint3D(dx,dy,dz);
428#endif
429    nodes.push_back(ExtNode(ppp));
430  }
431
432  //   S E T   F A C E S
433
434  for (int iface=1; iface <= p.GetNoFacets(); iface++) {
435    faces.push_back(ExtFace(edges,edges.size()));
436
437    //   S E T   F A C E   N O D E S
438
439    p.GetFacet(iface, nnode, iNodes, iVis, iFaces);
440    for (i=0; i<nnode; i++) {
441      //if (iNodes[i] < 1 || iNodes[i] > p.GetNoVertices()) processor_error = 1;
442      //if (iFaces[i] < 1 || iFaces[i] > p.GetNoFacets())   processor_error = 1;
443
444      if (iNodes[i] < 1 || iNodes[i] > p.GetNoVertices()) { //G.Barrand
445        processor_error = 1;
446#ifdef BP_DEBUG
447        std::cerr
448          << "BooleanProcessor::takePolyhedron : problem 1."
449          << std::endl;
450#endif
451      }
452      if (iFaces[i] < 1 || iFaces[i] > p.GetNoFacets()) { //G.Barrand
453        processor_error = 1;
454#ifdef BP_DEBUG
455        std::cerr
456          << "BooleanProcessor::takePolyhedron : problem 2."
457          << std::endl;
458#endif
459      }
460      iNodes[i] += dnode;
461      iFaces[i] += dface;
462    }
463
464    //   S E T   E D G E S
465
466    iNodes[nnode] = iNodes[0];
467    faces.back().iedges[3] = 0;
468    for (i=0; i<nnode; i++) {
469      faces.back().iedges[i] = edges.size();
470      edges.push_back(ExtEdge(iNodes[i], iNodes[i+1],
471                              iface+dface, iFaces[i], iVis[i]));
472      edges.back().inext     = edges.size();
473    }
474    edges.back().inext = 0;
475
476    //   S E T   F A C E   M I N - M A X
477
478    ExtFace& face = faces.back();     //G.Barrand : optimize.
479    for (i=0; i<3; i++) {
480      face.rmin[i] = nodes[iNodes[0]].v[i];
481      face.rmax[i] = nodes[iNodes[0]].v[i];
482    }
483    for (i=1; i<nnode; i++) {
484      ExtNode& node = nodes[iNodes[i]]; //G.Barrand : optimize.
485      for (k=0; k<3; k++) {
486        if (face.rmin[k] > node.v[k])
487            face.rmin[k] = node.v[k];
488        if (face.rmax[k] < node.v[k])
489            face.rmax[k] = node.v[k];
490      }
491    }
492
493    //   S E T   F A C E   P L A N E
494
495    HVNormal3D n = (nodes[iNodes[2]].v-nodes[iNodes[0]].v).cross
496                    (nodes[iNodes[3]].v-nodes[iNodes[1]].v);
497    HVPoint3D  p(0,0,0);
498   
499    for (i=0; i<nnode; i++) { p += nodes[iNodes[i]].v; }
500    p *= (1./nnode);
501    //G.Barrand : faces.back().plane = HVPlane3D(n.unit(), p);
502    faces.back().plane = HVPlane3D(n, p); //G.Barrand
503
504    //   S E T   R E F E R E N C E   T O   T H E   N E X T   F A C E
505
506    faces.back().inext = faces.size();
507  }
508  faces.back().inext = 0;
509}
510
511double BooleanProcessor::findMinMax()
512/***********************************************************************
513 *                                                                     *
514 * Name: BooleanProcessor::findMinMax                Date:    16.12.99 *
515 * Author: E.Chernyaev                               Revised:          *
516 *                                                                     *
517 * Function: Find min-max (bounding) boxes for polyhedra               *
518 *                                                                     *
519 ***********************************************************************/
520{
521  if (ifaces1 == 0 || ifaces2 == 0) return 0;
522
523  int    i, iface;
524  double rmin1[3], rmax1[3];
525  double rmin2[3], rmax2[3];
526
527  //   F I N D   B O U N D I N G   B O X E S
528
529  for (i=0; i<3; i++) {
530    rmin1[i] = faces[ifaces1].rmin[i];
531    rmax1[i] = faces[ifaces1].rmax[i];
532    rmin2[i] = faces[ifaces2].rmin[i];
533    rmax2[i] = faces[ifaces2].rmax[i];
534  }
535
536  iface = faces[ifaces1].inext;
537  while(iface > 0) {
538    ExtFace& face = faces[iface]; //G.Barrand
539    for (i=0; i<3; i++) {
540      if (rmin1[i] > face.rmin[i]) rmin1[i] = face.rmin[i];
541      if (rmax1[i] < face.rmax[i]) rmax1[i] = face.rmax[i];
542    }
543    iface = face.inext;
544  }
545
546  iface = faces[ifaces2].inext;
547  while(iface > 0) {
548    ExtFace& face = faces[iface]; //G.Barrand
549    for (i=0; i<3; i++) {
550      if (rmin2[i] > face.rmin[i]) rmin2[i] = face.rmin[i];
551      if (rmax2[i] < face.rmax[i]) rmax2[i] = face.rmax[i];
552    }
553    iface = face.inext;
554  }
555
556  //   F I N D   I N T E R S E C T I O N   O F   B O U N D I N G   B O X E S
557
558  for (i=0; i<3; i++) {
559    rmin[i] = (rmin1[i] > rmin2[i]) ? rmin1[i] : rmin2[i];
560    rmax[i] = (rmax1[i] < rmax2[i]) ? rmax1[i] : rmax2[i];
561  }
562
563  //   F I N D   T O L E R A N C E
564
565  double del1 = 0;
566  double del2 = 0;
567  for (i=0; i<3; i++) {
568    if ((rmax1[i]-rmin1[i]) > del1) del1 = rmax1[i]-rmin1[i];
569    if ((rmax2[i]-rmin2[i]) > del2) del2 = rmax2[i]-rmin2[i];
570  }
571  return ((del1 < del2) ? del1 : del2) / GRANULARITY;
572}
573
574void BooleanProcessor::selectOutsideFaces(int & ifaces, int & iout)
575/***********************************************************************
576 *                                                                     *
577 * Name: BooleanProcessor::selectOutsideFaces        Date:    10.01.00 *
578 * Author: E.Chernyaev                               Revised:          *
579 *                                                                     *
580 * Function: Preselection of outside faces                             *
581 *                                                                     *
582 ***********************************************************************/
583{
584  int i, outflag, iface = ifaces, *prev;
585  HVPoint3D mmbox[8] = { HVPoint3D(rmin[0],rmin[1],rmin[2]),
586                               HVPoint3D(rmax[0],rmin[1],rmin[2]),
587                               HVPoint3D(rmin[0],rmax[1],rmin[2]),
588                               HVPoint3D(rmax[0],rmax[1],rmin[2]),
589                               HVPoint3D(rmin[0],rmin[1],rmax[2]),
590                               HVPoint3D(rmax[0],rmin[1],rmax[2]),
591                               HVPoint3D(rmin[0],rmax[1],rmax[2]),
592                               HVPoint3D(rmax[0],rmax[1],rmax[2]) };
593  prev = &ifaces;
594  while (iface > 0) {
595
596    //   B O U N D I N G   B O X   vs  B O U N D I N G   B O X
597
598    outflag = 0;
599    ExtFace& face = faces[iface]; //G.Barrand : optimize.
600    for (i=0; i<3; i++) {
601      if (face.rmin[i] > rmax[i] + del) { outflag = 1; break; }
602      if (face.rmax[i] < rmin[i] - del) { outflag = 1; break; }
603    }
604
605    //   B O U N D I N G   B O X   vs  P L A N E
606
607    if (outflag == 0) {
608      int npos = 0, nneg = 0;
609      double d;
610      for (i=0; i<8; i++) {
611        d = face.plane.distance(mmbox[i]); //G.Barrand : optimize
612        if (d > +del) npos++;
613        if (d < -del) nneg++;
614      }
615      if (npos == 8 || nneg == 8) outflag = 1;
616    }
617
618    //   U P D A T E   L I S T S
619
620    if (outflag == 1) {
621      *prev = face.inext;
622      face.inext = iout;
623      iout = iface;
624    }else{
625      prev = &face.inext;
626    }
627
628    iface = *prev;
629  }
630}
631
632int BooleanProcessor::testFaceVsPlane(ExtEdge & edge)
633/***********************************************************************
634 *                                                                     *
635 * Name: BooleanProcessor::testFaceVsPlane           Date:    19.01.00 *
636 * Author: E.Chernyaev                               Revised:          *
637 *                                                                     *
638 * Function: Find result of intersection of face by plane              *
639 *                                                                     *
640 ***********************************************************************/
641{
642  int        iface = edge.iface1;
643  HVPlane3D plane = faces[edge.iface2].plane;
644  int        i, nnode, npos = 0, nneg = 0, nzer = 0;
645  double     dd[5];
646
647  //   F I N D   D I S T A N C E S
648
649  nnode = (faces[iface].iedges[3] == 0) ? 3 : 4;
650  for (i=0; i<nnode; i++) {
651    dd[i] = plane.distance(nodes[edges[faces[iface].iedges[i]].i1].v);
652    if (dd[i] > del) {
653      npos++;
654    }else if (dd[i] < -del) {
655      nneg++;
656    }else{
657      nzer++; dd[i] = 0;
658    } 
659  }
660
661  //   S O M E   S I M P L E   C A S E S  ( N O   I N T E R S E C T I O N )
662
663  if (npos == nnode || nneg == nnode)   return OUT_OF_PLANE;
664  if (nzer == 1     && nneg == 0)       return OUT_OF_PLANE;
665  if (nzer == 1     && npos == 0)       return OUT_OF_PLANE;
666  if (nzer == nnode)                    return ON_PLANE;
667  if (nzer == 3)                        return NON_PLANAR_FACE;
668
669  //   F I N D   I N T E R S E C T I O N
670
671  int       ie1 = 0, ie2 = 0, s1 = 0, s2 = 0, status, nint = 0;
672  enum      { PLUS_MINUS, MINUS_PLUS, ZERO_ZERO, ZERO_PLUS, ZERO_MINUS };
673
674  dd[nnode] = dd[0];
675  for (i=0; i<nnode; i++) {
676    if (dd[i] > 0) {
677      if (dd[i+1] >= 0) continue;
678      status = PLUS_MINUS;
679    }else if (dd[i] < 0) {
680      if (dd[i+1] <= 0) continue;
681      status = MINUS_PLUS;
682    }else{   
683      status = ZERO_ZERO;
684      if (dd[i+1] > 0) status = ZERO_PLUS;
685      if (dd[i+1] < 0) status = ZERO_MINUS;
686    }
687    switch (nint) {
688    case 0:
689      ie1 = i; s1 = status; nint++; break;
690    case 1:
691      ie2 = i; s2 = status; nint++; break;
692    default:
693      return NON_PLANAR_FACE;
694    }
695  }
696  if (nint != 2)                        return NON_PLANAR_FACE;
697
698  //   F O R M   I N T E R S E C T I O N   S E G M E N T
699
700  if (s1 != ZERO_ZERO && s2 != ZERO_ZERO) {
701    if (s1 == s2)                       return NON_PLANAR_FACE;
702    int     iedge, i1 = 0, i2 = 0, ii[2];
703    double  d1 = 0., d2 = 0., dd ;
704    ii[0] = ie1; ii[1] = ie2;
705    for (i=0; i<2; i++) {
706      iedge = faces[iface].iedges[ii[i]];
707      while (iedge > 0) {
708        i1 = edges[iedge].i1;
709        i2 = edges[iedge].i2;
710   
711        d1 = plane.distance(nodes[i1].v);
712        d2 = plane.distance(nodes[i2].v);
713        if (d1 > del) {
714          if (d2 < -del) { ii[i] = nodes.size(); break; } // +-
715        }else if (d1 < -del) {
716          if (d2 >  del) { ii[i] = nodes.size(); break; } // -+
717        }else{
718          ii[i] = i1; break;                              // 0+ or 0-
719        }
720        iedge = edges[iedge].inext;
721      }
722      if (ii[i] == (int)nodes.size()) {
723        dd = d2-d1; d1 = d1/dd; d2 = d2/dd;
724        nodes.push_back(ExtNode(d2*nodes[i1].v-d1*nodes[i2].v, iedge));
725      } 
726    }
727    edge.inext = 0;
728    if (s1 == MINUS_PLUS || s1 == ZERO_PLUS) {
729      edge.i1 = ii[1];
730      edge.i2 = ii[0];
731    }else{
732      edge.i1 = ii[0];
733      edge.i2 = ii[1];
734    }
735    return INTERSECTION;
736  }else{
737    if (npos == nneg)                   return NON_PLANAR_FACE;
738    edge.inext = (s1 == ZERO_ZERO) ? ie1+1 : ie2+1;
739    if (s1 == ZERO_PLUS || s2 == ZERO_MINUS) {
740      edge.i1 = edges[faces[iface].iedges[ie2]].i1;
741      edge.i2 = edges[faces[iface].iedges[ie1]].i1;
742    }else{
743      edge.i1 = edges[faces[iface].iedges[ie1]].i1;
744      edge.i2 = edges[faces[iface].iedges[ie2]].i1;
745    }
746    return EDGE;
747  }
748}
749
750void BooleanProcessor::renumberNodes(int & i1, int & i2, int & i3, int & i4)
751/***********************************************************************
752 *                                                                     *
753 * Name: BooleanProcessor::renumberNodes             Date:    19.01.00 *
754 * Author: E.Chernyaev                               Revised:          *
755 *                                                                     *
756 * Function: Renumber nodes and remove last temporary node.            *
757 *           Remark: In principal this routine can be replaced just    *
758 *           with i1 = i2;                                             *
759 *           Removal of temporary nodes provides additional control    *
760 *           on number of nodes, that is very useful for debugging.    *
761 *                                                                     *
762 ***********************************************************************/
763{
764  if (i1 == i2) return;
765  if (nodes[i1].s == 0 || nodes.back().s == 0) { i1 = i2; return; }
766
767  int ilast = nodes.size()-1;
768  if (i1 == ilast) { i1 = i2; nodes.pop_back(); return; }
769  if (i2 == ilast) { i2 = i1; }
770  if (i3 == ilast) { i3 = i1; }
771  if (i4 == ilast) { i4 = i1; }
772  nodes[i1] = nodes.back(); i1 = i2; nodes.pop_back();
773}
774
775int BooleanProcessor::testEdgeVsEdge(ExtEdge & edge1, ExtEdge & edge2)
776/***********************************************************************
777 *                                                                     *
778 * Name: BooleanProcessor::testEdgeVsEdge            Date:    19.01.00 *
779 * Author: E.Chernyaev                               Revised:          *
780 *                                                                     *
781 * Function: Find common part of two edges                             *
782 *                                                                     *
783 ***********************************************************************/
784{
785  int    i, ii = 0;
786  double d, dd = 0.;
787
788  for (i=0; i<3; i++) {
789    d = nodes[edge1.i1].v[i]-nodes[edge1.i2].v[i];
790    if (d < 0.) d = -d;
791    if (d > dd) { dd = d; ii = i; }
792  }
793  double t1 = nodes[edge1.i1].v[ii];
794  double t2 = nodes[edge1.i2].v[ii];
795  double t3 = nodes[edge2.i1].v[ii];
796  double t4 = nodes[edge2.i2].v[ii];
797  if (t2-t1 < 0.) { t1 = -t1; t2 = -t2; t3 = -t3; t4 = -t4; }
798 
799  if (t3 <= t1+del || t4 >= t2-del) return 0;
800  if (t3 > t2+del) {
801    renumberNodes(edge2.i1, edge1.i2, edge1.i1, edge2.i2);
802  }else if (t3 < t2-del) {
803    renumberNodes(edge1.i2, edge2.i1, edge1.i1, edge2.i2);
804  }
805  if (t4 < t1-del) {
806    renumberNodes(edge2.i2, edge1.i1, edge1.i2, edge2.i1);
807  }else if (t4 > t1+del) {
808    renumberNodes(edge1.i1, edge2.i2, edge1.i2, edge2.i1);
809  }
810  return 1;
811}
812
813void BooleanProcessor::divideEdge(int & i1, int & i2)
814/***********************************************************************
815 *                                                                     *
816 * Name: BooleanProcessor::divideEdge                Date:    24.01.00 *
817 * Author: E.Chernyaev                               Revised:          *
818 *                                                                     *
819 * Function: Unify the nodes and divide edge on two parts by the node. *
820 *                                                                     *
821 ***********************************************************************/
822{
823  int iedges[2];
824  iedges[0] = nodes[i1].s;
825  iedges[1] = nodes[i2].s;
826
827  //   U N I F Y   N O D E S
828 
829  if      (i1 < i2) { i2 = i1; }
830  else if (i1 > i2) { i1 = i2; }
831  else              { iedges[1] = 0; } 
832  if (iedges[0] == iedges[1]) return;
833
834  int ie1, ie2, inode = i1;
835  nodes[inode].s = 0;
836  for (int i=0; i<2; i++) {
837
838    //   F I N D   C O R R E S P O N D I N G   E D G E
839
840    if ((ie1 = iedges[i]) == 0) continue;
841    ie2 = faces[edges[ie1].iface2].iedges[0];
842    while (ie2 > 0) {
843      if (edges[ie2].i1 == edges[ie1].i2 &&
844          edges[ie2].i2 == edges[ie1].i1) break;
845      ie2 = edges[ie2].inext;
846    }
847
848    //   D I V I D E   E D G E S
849   
850    edges.push_back(edges[ie1]);
851    edges[ie1].inext = edges.size() - 1;
852    edges[ie1].i2    = inode;
853    edges.back().i1  = inode;
854   
855    edges.push_back(edges[ie2]);
856    edges[ie2].inext = edges.size() - 1;
857    edges[ie2].i2    = inode;
858    edges.back().i1  = inode;
859  }
860}
861
862void BooleanProcessor::insertEdge(const ExtEdge & edge)
863/***********************************************************************
864 *                                                                     *
865 * Name: BooleanProcessor::insertEdge                Date:    24.01.00 *
866 * Author: E.Chernyaev                               Revised:          *
867 *                                                                     *
868 * Function: Insert edge to the list of new edges                      *
869 *                                                                     *
870 ***********************************************************************/
871{
872  int iface = edge.iface1;
873  edges.push_back(edge);
874  edges.back().inext = faces[iface].inew;
875  faces[iface].inew  = edges.size() - 1;
876}
877
878void BooleanProcessor::caseII(ExtEdge & edge1, ExtEdge & edge2)
879/***********************************************************************
880 *                                                                     *
881 * Name: BooleanProcessor::caseII                    Date:    19.01.00 *
882 * Author: E.Chernyaev                               Revised:          *
883 *                                                                     *
884 * Function: Intersection/Intersection case                            *
885 *                                                                     *
886 ***********************************************************************/
887{
888  divideEdge(edge1.i1, edge2.i2);
889  divideEdge(edge1.i2, edge2.i1);
890  edge1.ivis = 1;
891  edge2.ivis = 1;
892  insertEdge(edge1);
893  insertEdge(edge2);
894}
895
896void BooleanProcessor::caseIE(ExtEdge &, ExtEdge &)
897/***********************************************************************
898 *                                                                     *
899 * Name: BooleanProcessor::caseIE                    Date:    19.01.00 *
900 * Author: E.Chernyaev                               Revised:          *
901 *                                                                     *
902 * Function: Intersection/Edge-touch case                              *
903 *                                                                     *
904 ***********************************************************************/
905{
906  processor_error = 1;
907#ifdef BP_DEBUG
908  std::cout
909    << "BooleanProcessor::caseIE : unimplemented case"
910    << std::endl;
911#endif
912}
913
914void BooleanProcessor::caseEE(ExtEdge &, ExtEdge &)
915/***********************************************************************
916 *                                                                     *
917 * Name: BooleanProcessor::caseEE                    Date:    19.01.00 *
918 * Author: E.Chernyaev                               Revised:          *
919 *                                                                     *
920 * Function: Edge-touch/Edge-touch case                                *
921 *                                                                     *
922 ***********************************************************************/
923{
924  processor_error = 1;
925#ifdef BP_DEBUG
926  std::cout
927    << "BooleanProcessor::caseEE : unimplemented case"
928    << std::endl;
929#endif
930}
931
932void BooleanProcessor::testFaceVsFace(int iface1, int iface2)
933/***********************************************************************
934 *                                                                     *
935 * Name: BooleanProcessor::testFaceVsFace            Date:    11.01.00 *
936 * Author: E.Chernyaev                               Revised:          *
937 *                                                                     *
938 * Function: Find result (an edge) of intersection of two faces        *
939 *                                                                     *
940 ***********************************************************************/
941{
942  ExtEdge edge1, edge2;
943  int     irep1, irep2;
944
945  //   M I N - M A X
946
947 {const ExtFace& face_1 = faces[iface1]; //G.Barrand : optimize
948  const ExtFace& face_2 = faces[iface2];
949  for (int i=0; i<3; i++) {
950    if (face_1.rmin[i] > face_2.rmax[i] + del) return;
951    if (face_1.rmax[i] < face_2.rmin[i] - del) return;
952  }}
953
954  //   F A C E - 1   vs   P L A N E - 2
955
956  edge1.iface1 = iface1;
957  edge1.iface2 = iface2;
958  irep1        = testFaceVsPlane(edge1);
959  if (irep1 == OUT_OF_PLANE || irep1 == ON_PLANE) {
960    removeJunkNodes();
961    return;
962  }
963
964  //   F A C E - 2   vs   P L A N E - 1
965
966  edge2.iface1 = iface2;
967  edge2.iface2 = iface1;
968  irep2        = testFaceVsPlane(edge2);
969  if (irep2 == OUT_OF_PLANE || irep2 == ON_PLANE) {
970    removeJunkNodes();
971    return;
972  }
973
974  //   C H E C K   F O R   N O N P L A N A R   F A C E
975
976  if (irep1 == NON_PLANAR_FACE || irep2 == NON_PLANAR_FACE) {
977    removeJunkNodes();
978    return;
979  }
980
981  //   F I N D   I N T E R S E C T I O N   P A R T
982
983  if (testEdgeVsEdge(edge1, edge2) == 0) return;
984
985  //   C O N S I D E R   D I F F E R E N T   C A S E S 
986
987  if (irep1 == INTERSECTION && irep2 == INTERSECTION) caseII(edge1, edge2);
988  if (irep1 == INTERSECTION && irep2 == EDGE)         caseIE(edge1, edge2);
989  if (irep1 == EDGE         && irep2 == INTERSECTION) caseIE(edge2, edge1);
990  if (irep1 == EDGE         && irep2 == EDGE)         caseEE(edge1, edge2);
991  removeJunkNodes();
992
993}
994
995void BooleanProcessor::invertNewEdges(int iface)
996/***********************************************************************
997 *                                                                     *
998 * Name: BooleanProcessor::invertNewEdges            Date:    04.02.00 *
999 * Author: E.Chernyaev                               Revised:          *
1000 *                                                                     *
1001 * Function: Invert direction of new edges                             *
1002 *                                                                     *
1003 ***********************************************************************/
1004{
1005  int iedge = faces[iface].inew;
1006  while (iedge > 0) {
1007    edges[iedge].invert();
1008    iedge = edges[iedge].inext;
1009  }
1010}
1011
1012void BooleanProcessor::checkDoubleEdges(int)
1013/***********************************************************************
1014 *                                                                     *
1015 * Name: BooleanProcessor::checkDoubleEdges          Date:    04.02.00 *
1016 * Author: E.Chernyaev                               Revised:          *
1017 *                                                                     *
1018 * Function: Eliminate duplication of edges                            *
1019 *                                                                     *
1020 ***********************************************************************/
1021{
1022
1023}
1024
1025void BooleanProcessor::assembleFace(int what, int iface)
1026/***********************************************************************
1027 *                                                                     *
1028 * Name: BooleanProcessor::assembleFace              Date:    19.02.00 *
1029 * Author: E.Chernyaev                               Revised:          *
1030 *                                                                     *
1031 * Function: Assemble face                                             *
1032 *                                                                     *
1033 ***********************************************************************/
1034{
1035  //   A S S E M B L E   N E W   F A C E
1036
1037  int ihead;      // head of the list of edges for new face
1038  int icur;       // current edge in the list - last edge inserted to the list
1039  int *ilink;     // pointer to the current link
1040  int ifirst;     // first node of a contour
1041  int *i;         // pointer to the index of the current edge in a loop
1042  int ioldflag=0; // is set if an edge from iold has been taken
1043
1044#define INSERT_EDGE_TO_THE_LIST(A) \
1045*ilink = A; ilink = &edges[A].inext; *ilink = 0
1046
1047  ExtFace& face = faces[iface]; //G.Barrand : optimize.
1048  ilink = &ihead;
1049  for(;;) {
1050    if (face.inew == 0) break;
1051
1052    //   S T A R T   N E W   C O N T O U R
1053
1054    icur   = face.inew;
1055    face.inew = edges[icur].inext;
1056    INSERT_EDGE_TO_THE_LIST(icur);
1057    ifirst = edges[icur].i1;
1058   
1059    //   C O N S T R U C T   T H E   C O N T O U R
1060
1061    for (;;) {
1062      i = &face.inew;
1063      ExtEdge& edge_cur = edges[icur];
1064      while(*i > 0) {
1065        ExtEdge& edge_i = edges[*i];
1066        if (edge_i.i1 == edge_cur.i2) break;
1067        i = &edge_i.inext;
1068      }
1069      if (*i == 0) {
1070        i = &face.iold;   
1071        while(*i > 0) {       
1072          ExtEdge& edge_i = edges[*i];
1073          if (edge_i.i1 == edge_cur.i2) {
1074            ioldflag = 1;
1075            break;
1076          }
1077          i = &edge_i.inext;
1078        }
1079      }
1080      if (*i > 0) {
1081        icur = *i;
1082        *i = edges[icur].inext;
1083        INSERT_EDGE_TO_THE_LIST(icur);
1084        if (edges[icur].i2 == ifirst) { break; } else { continue; }
1085      }else{
1086        processor_error = 1;
1087#ifdef BP_DEBUG
1088        std::cerr
1089          << "BooleanProcessor::assembleFace(" << iface << ") : "
1090          << "could not find next edge of the contour"
1091          << std::endl;
1092#endif
1093        face.inew = DEFECTIVE_FACE;
1094        return;
1095      }
1096    }
1097  }
1098
1099  //   C H E C K   O R I G I N A L   C O N T O U R
1100
1101  int iedge;
1102  iedge = face.iold;
1103  if (what == 0 && ioldflag == 0 && iedge > 0) {
1104    for (;;) {
1105      if (edges[iedge].inext > 0) {
1106        if (edges[iedge].i2 == edges[edges[iedge].inext].i1) {
1107          iedge = edges[iedge].inext;
1108        }else{
1109          break;
1110        }
1111      }else{
1112        if (edges[iedge].i2 == edges[face.iold].i1) {
1113          edges[iedge].inext = ihead;   // set new face
1114          return;
1115        }else{
1116          break;
1117        }
1118      }
1119    }
1120  }
1121
1122  //   M A R K   U N S U I T A B L E   N E I G H B O U R I N G   F A C E S
1123
1124  int iface2;
1125  iedge = face.iold;
1126  while(iedge > 0) {
1127    iface2 = edges[iedge].iface2;
1128    if (faces[iface2].inew == 0) faces[iface2].inew = UNSUITABLE_FACE;
1129    iedge = edges[iedge].inext;
1130  }
1131  face.iold = ihead;            // set new face
1132}
1133
1134void BooleanProcessor::assembleNewFaces(int what, int ihead)
1135/***********************************************************************
1136 *                                                                     *
1137 * Name: BooleanProcessor::assembleNewFaces          Date:    30.01.00 *
1138 * Author: E.Chernyaev                               Revised:          *
1139 *                                                                     *
1140 * Function: Assemble internal or external parts of faces              *
1141 *                                                                     *
1142 ***********************************************************************/
1143{
1144  int iface = ihead;
1145  while(iface > 0) {
1146    if (faces[iface].inew > 0) {
1147      if (what != 0) invertNewEdges(iface);
1148      checkDoubleEdges(iface);
1149      assembleFace(what, iface);
1150      faces[iface].inew =
1151        (faces[iface].iold == 0) ? UNSUITABLE_FACE : NEW_FACE;
1152    }
1153    iface = faces[iface].inext;
1154  }
1155}
1156
1157void BooleanProcessor::initiateLists()
1158/***********************************************************************
1159 *                                                                     *
1160 * Name: BooleanProcessor::initiateLists             Date:    28.02.00 *
1161 * Author: E.Chernyaev                               Revised:          *
1162 *                                                                     *
1163 * Function: Initiate lists of faces.                                  *
1164 *                                                                     *
1165 ***********************************************************************/
1166{
1167  int i, iface;
1168
1169  //   R E S E T   L I S T S   O F   F A C E S
1170
1171  result_faces.clean();
1172  suitable_faces.clean();
1173  unsuitable_faces.clean();
1174  unknown_faces.clean();
1175
1176  //   I N I T I A T E   T H E   L I S T S
1177
1178  iface = iout1;
1179  while (iface > 0) {
1180    i     = iface;
1181    iface = faces[i].inext;
1182    if (operation == OP_INTERSECTION) {
1183      unsuitable_faces.push_back(i);
1184      faces[i].inew = UNSUITABLE_FACE;
1185    }else{
1186      suitable_faces.push_back(i);
1187      faces[i].inew = ORIGINAL_FACE;
1188    }
1189  }
1190  iface = iout2;
1191  while (iface > 0) {
1192    i     = iface;
1193    iface = faces[i].inext;
1194    if (operation == OP_UNION) {
1195      suitable_faces.push_back(i);
1196      faces[i].inew = ORIGINAL_FACE;
1197    }else{
1198      unsuitable_faces.push_back(i);
1199      faces[i].inew = UNSUITABLE_FACE;
1200    }
1201  }
1202
1203  iface = iunk1;
1204  while (iface > 0) {
1205    i     = iface;
1206    iface = faces[i].inext;
1207    unknown_faces.push_back(i);
1208  }
1209  iface = iunk2;
1210  while (iface > 0) {
1211    i     = iface;
1212    iface = faces[i].inext;
1213    if (operation == OP_SUBTRACTION) faces[i].invert();
1214    unknown_faces.push_back(i);
1215  }
1216
1217  iface = ifaces1;
1218  while (iface > 0) {
1219    i     = iface;
1220    iface = faces[i].inext;
1221    switch(faces[i].inew) {
1222    case UNKNOWN_FACE:
1223      unknown_faces.push_back(i);
1224      break;
1225    case ORIGINAL_FACE: case NEW_FACE:
1226      suitable_faces.push_back(i);
1227      break;
1228    case UNSUITABLE_FACE:
1229      unsuitable_faces.push_back(i);
1230      break;
1231    default:
1232      faces[i].iprev = 0;
1233      faces[i].inext = 0;
1234      break;
1235    }
1236  }
1237  iface = ifaces2;
1238  while (iface > 0) {
1239    i     = iface;
1240    iface = faces[i].inext;
1241    if (operation == OP_SUBTRACTION) faces[i].invert();
1242    switch(faces[i].inew) {
1243    case UNKNOWN_FACE:
1244      unknown_faces.push_back(i);
1245      break;
1246    case ORIGINAL_FACE: case NEW_FACE:
1247      suitable_faces.push_back(i);
1248      break;
1249    case UNSUITABLE_FACE:
1250      unsuitable_faces.push_back(i);
1251      break;
1252    default:
1253      faces[i].iprev = 0;
1254      faces[i].inext = 0;
1255      break;
1256    }
1257  }
1258  ifaces1 = ifaces2 = iout1 = iout2 = iunk1 = iunk2 = 0;
1259}
1260
1261void BooleanProcessor::assemblePolyhedra()
1262/***********************************************************************
1263 *                                                                     *
1264 * Name: BooleanProcessor::assemblePolyhedra()       Date:    10.12.99 *
1265 * Author: E.Chernyaev                               Revised:          *
1266 *                                                                     *
1267 * Function: Collect suitable faces and remove unsuitable ones.        *
1268 *                                                                     *
1269 ***********************************************************************/
1270{
1271  int i, iedge, iface;
1272
1273  //   L O O P   A L O N G   S U I T A B L E   F A C E S
1274
1275  iface = suitable_faces.front();
1276  while(iface > 0) {
1277    i = iface;
1278    iedge = faces[i].iold;
1279    while(iedge > 0) {
1280      iface = edges[iedge].iface2;
1281      if (faces[iface].inew == UNKNOWN_FACE) {
1282        unknown_faces.remove(iface);
1283        suitable_faces.push_back(iface);
1284        faces[iface].inew = ORIGINAL_FACE;
1285      }
1286      iedge = edges[iedge].inext;
1287    }
1288    iface = faces[i].inext;
1289    suitable_faces.remove(i);
1290    result_faces.push_back(i);
1291  }
1292  if (unknown_faces.front() == 0) return;
1293
1294  //   L O O P   A L O N G   U N S U I T A B L E   F A C E S
1295
1296  iface = unsuitable_faces.front();
1297  while(iface > 0) {
1298    i = iface;
1299    iedge = faces[i].iold;
1300    while(iedge > 0) {
1301      iface = edges[iedge].iface2;
1302      if (faces[iface].inew == UNKNOWN_FACE) {
1303        unknown_faces.remove(iface);
1304        unsuitable_faces.push_back(iface);
1305        faces[iface].inew = UNSUITABLE_FACE;
1306      }
1307      iedge = edges[iedge].inext;
1308    }
1309    iface = faces[i].inext;
1310    unsuitable_faces.remove(i);
1311  }
1312
1313  //G.Barrand : begin
1314  /* From S.Ponce
1315   At last, there is a problem in the assemblePolyhedra method. At least, I
1316  think it is there. The problem deals with boolean operations on solids,
1317  when one of the two contains entirely the other one. It has no sense for
1318  intersection and union but still has sense for subtraction. In this
1319  case, faces from the inner solid are stored in the unknown_faces
1320  FaceList. And an error occurs in the execute method. This may be correct
1321  for intersection and union but in the case of subtraction, one should do
1322  that in assemblePolyhedra :
1323  */
1324  //   Unknown faces are actually suitable face !!!
1325   iface = unknown_faces.front();
1326   while(iface > 0) {
1327     i = iface;
1328     faces[i].inew = ORIGINAL_FACE;
1329     iface = faces[i].inext;
1330     unknown_faces.remove(i);
1331     result_faces.push_back(i);
1332   }
1333  /*
1334   Otherwise, the inner hole that the second solid was building in the
1335  first one does not exist. I'm not very clear on what to do for unions
1336  and intersections. I think this kind of situation should be detected and
1337  one of the solid should simply be ignored.
1338  */
1339  //G.Barrand : end
1340}
1341
1342inline void
1343BooleanProcessor::findABC(double x1, double y1, double x2, double y2,
1344                          double &a, double &b, double &c) const
1345/***********************************************************************
1346 *                                                                     *
1347 * Name: BooleanProcessor::findABC                   Date:    07.03.00 *
1348 * Author: E.Chernyaev                               Revised:          *
1349 *                                                                     *
1350 * Function: Find line equation Ax+By+C=0                              *
1351 *                                                                     *
1352 ***********************************************************************/
1353{
1354  double w;
1355  a  = y1 - y2;
1356  b  = x2 - x1;
1357  //G.Barrand : w  = std::abs(a)+std::abs(b);
1358  w  = ::fabs(a)+::fabs(b); //G.Barrand
1359  a /= w;
1360  b /= w;
1361  c  = -(a*x2 + b*y2);
1362}
1363
1364int BooleanProcessor::checkDirection(double *x, double *y) const
1365/***********************************************************************
1366 *                                                                     *
1367 * Name: BooleanProcessor::checkDirection            Date:    06.03.00 *
1368 * Author: E.Chernyaev                               Revised:          *
1369 *                                                                     *
1370 * Function: Check direction of line 1-4                               *
1371 *                                                                     *
1372 ***********************************************************************/
1373{
1374  double a1, b1, c1, a2, b2, c2, d1, d2;
1375
1376  //   T E S T   L I N E   1 - 4   V S   E X T E R N A L   C O N T O U R
1377
1378  findABC(x[0], y[0], x[1], y[1], a1, b1, c1);
1379  findABC(x[1], y[1], x[2], y[2], a2, b2, c2);
1380  d1 = a1*x[4] + b1*y[4] + c1;
1381  d2 = a2*x[4] + b2*y[4] + c2;
1382  if (d1 <= del && d2 <= del)            return 1;
1383  if (! (d1 > del && d2 > del)) {
1384    if ( a1*x[2] + b1*y[2] + c1 >= -del) return 1;
1385  }
1386
1387  //   T E S T   L I N E   1 - 4   V S   I N T E R N A L   C O N T O U R
1388 
1389  findABC(x[3], y[3], x[4], y[4], a1, b1, c1);
1390  findABC(x[4], y[4], x[5], y[5], a2, b2, c2);
1391  d1 = a1*x[1] + b1*y[1] + c1;
1392  d2 = a2*x[1] + b2*y[1] + c2;
1393  if (d1 <= del && d2 <= del)            return 1;
1394  if (!(d1 > del && d2 > del)) {
1395    if ( a1*x[5] + b1*y[5] + c1 >= -del) return 1;
1396  }
1397  return 0;
1398}
1399
1400int BooleanProcessor::checkIntersection(int ix, int iy, int i1, int i2) const
1401/***********************************************************************
1402 *                                                                     *
1403 * Name: BooleanProcessor::checkDirection            Date:    06.03.00 *
1404 * Author: E.Chernyaev                               Revised:          *
1405 *                                                                     *
1406 * Function: Check line i1-i2 on intersection with contours            *
1407 *                                                                     *
1408 ***********************************************************************/
1409{
1410  //  F I N D   L I N E   E Q U A T I O N
1411
1412  double x1, y1, x2, y2, a1, b1, c1;
1413  x1 = nodes[i1].v[ix];
1414  y1 = nodes[i1].v[iy];
1415  x2 = nodes[i2].v[ix];
1416  y2 = nodes[i2].v[iy];
1417  findABC(x1, y1, x2, y2, a1, b1, c1);
1418
1419  //  L O O P   A L O N G   E X T E R N A L   C O N T O U R S
1420
1421  int icontour, iedge, k1, k2;
1422  double x3, y3, x4, y4, a2, b2, c2, d1, d2;
1423  for(icontour=0; icontour<(int)external_contours.size(); icontour++) {
1424    iedge = external_contours[icontour];
1425    while(iedge > 0) {
1426      k1 = edges[iedge].i1;
1427      k2 = edges[iedge].i2;
1428      iedge = edges[iedge].inext;
1429      if (k1 == i1 || k2 == i1) continue;
1430      if (k1 == i2 || k2 == i2) continue;
1431      x3 = nodes[k1].v[ix];
1432      y3 = nodes[k1].v[iy];
1433      x4 = nodes[k2].v[ix];
1434      y4 = nodes[k2].v[iy];
1435      d1 = a1*x3 + b1*y3 + c1;
1436      d2 = a1*x4 + b1*y4 + c1;
1437      if (d1 >  del && d2 >  del) continue;
1438      if (d1 < -del && d2 < -del) continue;
1439
1440      findABC(x3, y3, x4, y4, a2, b2, c2);
1441      d1 = a2*x1 + b2*y1 + c2;
1442      d2 = a2*x2 + b2*y2 + c2;
1443      if (d1 >  del && d2 >  del) continue;
1444      if (d1 < -del && d2 < -del) continue;
1445      return 1;
1446    }
1447  }
1448
1449  //  L O O P   A L O N G   E X T E R N A L   C O N T O U R S
1450
1451  for(icontour=0; icontour<(int)internal_contours.size(); icontour++) {
1452    iedge = internal_contours[icontour];
1453    while(iedge > 0) {
1454      k1 = edges[iedge].i1;
1455      k2 = edges[iedge].i2;
1456      iedge = edges[iedge].inext;
1457      if (k1 == i1 || k2 == i1) continue;
1458      if (k1 == i2 || k2 == i2) continue;
1459      x3 = nodes[k1].v[ix];
1460      y3 = nodes[k1].v[iy];
1461      x4 = nodes[k2].v[ix];
1462      y4 = nodes[k2].v[iy];
1463      d1 = a1*x3 + b1*y3 + c1;
1464      d2 = a1*x4 + b1*y4 + c1;
1465      if (d1 >  del && d2 >  del) continue;
1466      if (d1 < -del && d2 < -del) continue;
1467
1468      findABC(x3, y3, x4, y4, a2, b2, c2);
1469      d1 = a2*x1 + b2*y1 + c2;
1470      d2 = a2*x2 + b2*y2 + c2;
1471      if (d1 >  del && d2 >  del) continue;
1472      if (d1 < -del && d2 < -del) continue;
1473      return 1;
1474    }
1475  }
1476  return 0;
1477}
1478
1479void BooleanProcessor::mergeContours(int ix, int iy, int kext, int kint)
1480/***********************************************************************
1481 *                                                                     *
1482 * Name: BooleanProcessor::mergeContours             Date:    06.03.00 *
1483 * Author: E.Chernyaev                               Revised:          *
1484 *                                                                     *
1485 * Function: Attemp to merge internal contour with external one        *
1486 *                                                                     *
1487 ***********************************************************************/
1488{
1489  int    i1ext, i2ext, i1int, i2int, i, k[6];
1490  double x[6], y[6];
1491
1492  //   L O O P   A L O N G   E X T E R N A L   C O N T O U R
1493
1494  i1ext = external_contours[kext];
1495  while (i1ext > 0) {
1496    i2ext = edges[i1ext].inext;
1497    if (i2ext == 0) i2ext = external_contours[kext];
1498    k[0] = edges[i1ext].i1;
1499    k[1] = edges[i1ext].i2;
1500    k[2] = edges[i2ext].i2;
1501    for (i=0; i<3; i++) {
1502      x[i] = nodes[k[i]].v[ix];
1503      y[i] = nodes[k[i]].v[iy];
1504    }
1505
1506    //   L O O P   A L O N G   I N T E R N A L   C O N T O U R
1507
1508    i1int = internal_contours[kint];
1509    while (i1int > 0) {
1510      i2int = edges[i1int].inext;
1511      if (i2int == 0) i2int = internal_contours[kint];
1512      k[3] = edges[i1int].i1;
1513      k[4] = edges[i1int].i2;
1514      k[5] = edges[i2int].i2;
1515      for (i=3; i<6; i++) {
1516        x[i] = nodes[k[i]].v[ix];
1517        y[i] = nodes[k[i]].v[iy];
1518      }
1519
1520      //   T E S T   L I N E   K1 - K4
1521      //   I F   O K   T H E N   M E R G E   C O N T O U R S
1522
1523      if (checkDirection(x, y) == 0) {
1524        if (checkIntersection(ix, iy, k[1], k[4]) == 0) {
1525          i = i1int;
1526          for(;;) {
1527            if (edges[i].inext == 0) {
1528              edges[i].inext = internal_contours[kint];
1529              internal_contours[kint] = 0;
1530              break;
1531            }else{
1532              i = edges[i].inext;
1533            }
1534          }
1535          i = edges[i1int].iface1;
1536          edges.push_back(ExtEdge(k[1], k[4], i, -(edges.size()+1), -1));
1537          edges.back().inext = i2int;
1538          edges.push_back(ExtEdge(k[4], k[1], i, -(edges.size()-1), -1));
1539          edges.back().inext = edges[i1ext].inext;
1540          edges[i1ext].inext = edges.size()-2;
1541          edges[i1int].inext = edges.size()-1;
1542          return;
1543        }
1544      }
1545      i1int = edges[i1int].inext;
1546    }
1547    i1ext = edges[i1ext].inext;
1548  }
1549}
1550
1551int
1552BooleanProcessor::checkTriangle(int iedge1, int iedge2, int ix, int iy) const
1553/***********************************************************************
1554 *                                                                     *
1555 * Name: BooleanProcessor::checkTriangle             Date:    08.03.00 *
1556 * Author: E.Chernyaev                               Revised:          *
1557 *                                                                     *
1558 * Function: Check triangle for correctness                            *
1559 *                                                                     *
1560 ***********************************************************************/
1561{
1562  int    k[3];
1563  double x[3], y[3];
1564  double a1, b1, c1;
1565
1566  k[0] = edges[iedge1].i1;
1567  k[1] = edges[iedge1].i2;
1568  k[2] = edges[iedge2].i2;
1569  for (int i=0; i<3; i++) {
1570    x[i] = nodes[k[i]].v[ix];
1571    y[i] = nodes[k[i]].v[iy];
1572  }
1573
1574  //  C H E C K   P R I N C I P A L   C O R R E C T N E S S 
1575   
1576  findABC(x[2], y[2], x[0], y[0], a1, b1, c1);
1577  if (a1*x[1]+b1*y[1]+c1 <= 0.1*del) return 1;
1578
1579  //   C H E C K   T H A T   T H E R E   I S   N O   P O I N T S   I N S I D E
1580
1581  int    inode, iedge;
1582  double a2, b2, c2, a3, b3, c3;
1583
1584  findABC(x[0], y[0], x[1], y[1], a2, b2, c2);
1585  findABC(x[1], y[1], x[2], y[2], a3, b3, c3);
1586  iedge = iedge2;
1587  for (;;) {
1588    iedge = edges[iedge].inext;
1589    if (edges[iedge].inext == iedge1) return 0;
1590    inode = edges[iedge].i2;
1591    if (inode == k[0])                continue;
1592    if (inode == k[1])                continue;
1593    if (inode == k[2])                continue;
1594    x[1]  = nodes[inode].v[ix];
1595    y[1]  = nodes[inode].v[iy];
1596    if (a1*x[1]+b1*y[1]+c1 < -0.1*del)    continue;
1597    if (a2*x[1]+b2*y[1]+c2 < -0.1*del)    continue;
1598    if (a3*x[1]+b3*y[1]+c3 < -0.1*del)    continue;
1599    return 1;
1600  }
1601}
1602
1603void BooleanProcessor::triangulateContour(int ix, int iy, int ihead)
1604/***********************************************************************
1605 *                                                                     *
1606 * Name: BooleanProcessor::triangulateContour        Date:    06.03.00 *
1607 * Author: E.Chernyaev                               Revised:          *
1608 *                                                                     *
1609 * Function: Triangulate external contour                              *
1610 *                                                                     *
1611 ***********************************************************************/
1612{
1613   
1614  //std::cout << "Next Countour" << std::endl;
1615  //int draw_flag = 0;
1616  //if (draw_flag) draw_contour(5, 3, ihead);
1617   
1618  //   C L O S E   C O N T O U R
1619 
1620  int ipnext = ihead, nnode = 1;
1621  for (;;) {
1622    if (edges[ipnext].inext > 0) {
1623      ipnext = edges[ipnext].inext;
1624      nnode++;
1625    }else{
1626      edges[ipnext].inext = ihead;
1627      break;
1628    }
1629  }
1630
1631  //   L O O P   A L O N G   C O N T O U R 
1632
1633  //std::cerr << "debug : contour : begin : =================" << std::endl;
1634  //dump();//debug
1635
1636  int iedge1, iedge2, iedge3, istart = 0;
1637  for (;;) {
1638    iedge1 = edges[ipnext].inext;
1639    iedge2 = edges[iedge1].inext;
1640/*
1641    std::cerr << "debug :"
1642              << " ipnext " << ipnext
1643              << " iedge1 " << iedge1
1644              << " iedge2 " << iedge2
1645              << " : istart " << istart
1646              << std::endl;
1647*/
1648    if (istart == 0) {
1649      istart = iedge1;
1650      if (nnode <= 3) {
1651        iedge3 = edges[iedge2].inext;
1652        edges[iedge1].iface1 = faces.size();
1653        edges[iedge2].iface1 = faces.size();
1654        edges[iedge3].iface1 = faces.size();
1655        edges[iedge3].inext = 0;
1656        faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ?
1657        faces.back().iold = iedge1;
1658        faces.back().inew = ORIGINAL_FACE;
1659
1660  //if (draw_flag) draw_contour(4, 2, iedge1);
1661
1662        break;
1663      }
1664    }else if (istart == iedge1) {
1665      processor_error = 1;
1666#ifdef BP_DEBUG
1667      std::cerr
1668        << "BooleanProcessor::triangulateContour : "
1669        << "could not generate a triangle (infinite loop)"
1670        << std::endl;
1671#endif
1672      break;
1673    }
1674
1675    //   C H E C K   C O R E C T N E S S   O F   T H E   T R I A N G L E
1676
1677    if (checkTriangle(iedge1,iedge2,ix,iy) != 0) {
1678      ipnext  = edges[ipnext].inext;
1679      continue;
1680    }
1681
1682    //   M O D I F Y   C O N T O U R 
1683   
1684    int i1 = edges[iedge1].i1;
1685    int i3 = edges[iedge2].i2;
1686    int iface1 = edges[iedge1].iface1;
1687    int iface2 = faces.size();
1688
1689    edges[ipnext].inext = edges.size();
1690    edges.push_back(ExtEdge(i1, i3, iface1, -(edges.size()+1), -1));
1691    edges.back().inext = edges[iedge2].inext;
1692
1693    //   A D D   N E W   T R I A N G L E   T O   T H E   L I S T
1694
1695    edges[iedge2].inext = edges.size();
1696    edges.push_back(ExtEdge(i3, i1, iface2, -(edges.size()-1), -1));
1697    faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ?
1698    faces.back().iold   = iedge1;
1699    faces.back().inew   = ORIGINAL_FACE;
1700    edges[iedge1].iface1 = iface2;
1701    edges[iedge2].iface1 = iface2;
1702    ipnext  = edges[ipnext].inext;
1703    istart = 0;
1704    nnode--;
1705
1706  //if (draw_flag)  draw_contour(4, 2, iedge1);
1707
1708  }
1709}
1710
1711void BooleanProcessor::modifyReference(int iface, int i1, int i2, int iref)
1712/***********************************************************************
1713 *                                                                     *
1714 * Name: BooleanProcessor::modifyReference           Date:    13.03.00 *
1715 * Author: E.Chernyaev                               Revised:          *
1716 *                                                                     *
1717 * Function: Modify reference to the neighbouring face                 *
1718 *                                                                     *
1719 ***********************************************************************/
1720{
1721  int iedge = faces[iface].iold;
1722  while (iedge > 0) {
1723    if (edges[iedge].i1 == i2 && edges[iedge].i2 == i1) {
1724      edges[iedge].iface2 = iref;
1725      return;
1726    }
1727    iedge = edges[iedge].inext;
1728  }
1729  processor_error = 1;
1730#ifdef BP_DEBUG
1731  std::cerr
1732    << "BooleanProcessor::modifyReference : could not find the edge, "
1733    << "iface=" << iface << ", i1,i2=" << i1 << "," << i2 << ", iref=" << iref
1734    << std::endl;
1735#endif
1736}
1737
1738void BooleanProcessor::triangulateFace(int iface)
1739/***********************************************************************
1740 *                                                                     *
1741 * Name: BooleanProcessor::triangulateFace           Date:    02.03.00 *
1742 * Author: E.Chernyaev                               Revised:          *
1743 *                                                                     *
1744 * Function: Triangulation of an extended face                         *
1745 *                                                                     *
1746 ***********************************************************************/
1747{
1748
1749  //   F I N D   M A X   C O M P O N E N T   O F   T H E   N O R M A L
1750  //   S E T  IX, IY, IZ
1751
1752#ifdef BP_GEANT4 //G.Barrand
1753  HVNormal3D normal = faces[iface].plane.normal();
1754#else
1755  const HVNormal3D& normal = faces[iface].plane.getNormal();
1756#endif
1757  int ix, iy, iz = 0;
1758  //G.Barrand : if (std::abs(normal[1]) > std::abs(normal[iz])) iz = 1;
1759  //G.Barrand : if (std::abs(normal[2]) > std::abs(normal[iz])) iz = 2;
1760  if (::fabs(normal[1]) > ::fabs(normal[iz])) iz = 1; //G.Barrand
1761  if (::fabs(normal[2]) > ::fabs(normal[iz])) iz = 2; //G.Barrand
1762  if (normal[iz] > 0) {
1763    ix = (iz+1)%3; iy = (ix+1)%3;
1764  }else{
1765    iy = (iz+1)%3; ix = (iy+1)%3;
1766  }
1767
1768  //   F I L L   L I S T S   O F   C O N T O U R S
1769
1770  external_contours.clear();
1771  internal_contours.clear();
1772  double z;
1773  int    i1, i2, ifirst, iedge, icontour = faces[iface].iold;
1774  while (icontour > 0) {
1775    iedge  = icontour;
1776    ifirst = edges[iedge].i1;
1777    z      = 0.0;
1778    for(;;) {
1779      if (iedge > 0) {
1780        i1 = edges[iedge].i1;
1781        i2 = edges[iedge].i2;
1782        ExtNode& node_1 = nodes[i1];
1783        ExtNode& node_2 = nodes[i2];
1784        z += node_1.v[ix]*node_2.v[iy]-node_2.v[ix]*node_1.v[iy];
1785        if (ifirst != i2) {
1786          iedge = edges[iedge].inext;
1787          continue;
1788        }else{
1789          if (z > del*del) {
1790            external_contours.push_back(icontour);
1791          }else if (z < -del*del) {
1792            internal_contours.push_back(icontour);
1793          }else{ 
1794            processor_error = 1;
1795#ifdef BP_DEBUG
1796            std::cerr
1797              << "BooleanProcessor::triangulateFace : too small contour"
1798              << std::endl;
1799#endif
1800          }
1801          icontour = edges[iedge].inext;
1802          edges[iedge].inext = 0;
1803          break;
1804        }
1805      }else{
1806        processor_error = 1;
1807#ifdef BP_DEBUG
1808        std::cerr
1809          << "BooleanProcessor::triangulateFace : broken contour"
1810          << std::endl;
1811#endif
1812        icontour = 0;
1813        break;
1814      }
1815    }
1816  }
1817
1818  //   G E T   R I D   O F   I N T E R N A L   C O N T O U R S
1819
1820  int kint, kext;
1821  for (kint=0; kint < (int)internal_contours.size(); kint++) {
1822    for (kext=0; kext < (int)external_contours.size(); kext++) {
1823      mergeContours(ix, iy, kext, kint);
1824      if (internal_contours[kint] == 0) break;
1825    }
1826    if (kext == (int)external_contours.size()) {
1827      processor_error = 1;
1828#ifdef BP_DEBUG
1829      std::cerr
1830        << "BooleanProcessor::triangulateFace : "
1831        << "could not merge internal contour " << kint
1832        << std::endl;
1833#endif
1834    }     
1835  }
1836
1837  //   T R I A N G U L A T E   C O N T O U R S
1838
1839  int nface = faces.size();
1840  for (kext=0; kext < (int)external_contours.size(); kext++) {
1841    triangulateContour(ix, iy, external_contours[kext]);
1842#ifdef BP_DEBUG
1843    if(processor_error) { //G.Barrand
1844      std::cerr
1845        << "BooleanProcessor::triangulateFace : "
1846        << "triangulateContour failed."
1847        << std::endl;
1848      break; //G.Barrand : ok ?
1849    }
1850#endif     
1851  }
1852  faces[iface].inew = UNSUITABLE_FACE;
1853
1854  //   M O D I F Y   R E F E R E N C E S
1855
1856  for (int ifa=nface; ifa<(int)faces.size(); ifa++) {
1857    iedge = faces[ifa].iold;
1858    while (iedge > 0) {
1859      if (edges[iedge].iface1 != ifa) {
1860        processor_error = 1;
1861#ifdef BP_DEBUG
1862        std::cerr
1863          << "BooleanProcessor::triangulateFace : wrong reference to itself, "
1864          << "iface=" << ifa << ", iface1=" << edges[iedge].iface1
1865          << std::endl;
1866#endif
1867      }else if (edges[iedge].iface2 > 0) {
1868        modifyReference(edges[iedge].iface2,
1869                        edges[iedge].i1, edges[iedge].i2, ifa);
1870      }else if (edges[iedge].iface2 < 0) {
1871        edges[iedge].iface2 = edges[-edges[iedge].iface2].iface1;
1872      }
1873      iedge = edges[iedge].inext;
1874    }
1875  }
1876}
1877
1878HepPolyhedron BooleanProcessor::createPolyhedron()
1879/***********************************************************************
1880 *                                                                     *
1881 * Name: BooleanProcessor::createPolyhedron()        Date:    14.03.00 *
1882 * Author: E.Chernyaev                               Revised:          *
1883 *                                                                     *
1884 * Function: Create HepPolyhedron.                                     *
1885 *                                                                     *
1886 ***********************************************************************/
1887{
1888  int i, iedge, nnode = 0, nface = 0;
1889
1890  //   R E N U M E R A T E   N O D E S   A N D   F A C E S
1891
1892  for (i=1; i<(int)nodes.size(); i++) nodes[i].s = 0;
1893
1894  for (i=1; i<(int)faces.size(); i++) {
1895    if (faces[i].inew == ORIGINAL_FACE) {
1896      faces[i].inew = ++nface;
1897      iedge = faces[i].iold;
1898      while (iedge > 0) {
1899        nodes[edges[iedge].i1].s = 1;
1900        iedge = edges[iedge].inext;
1901      }
1902    }else{
1903      faces[i].inew = 0;
1904    }
1905  }
1906
1907  for (i=1; i<(int)nodes.size(); i++) {
1908    if (nodes[i].s == 1) nodes[i].s = ++nnode;
1909  }
1910
1911  //   A L L O C A T E   M E M O R Y
1912
1913  ExtPolyhedron polyhedron;
1914  if (nface == 0) return polyhedron;
1915  polyhedron.AllocateMemory(nnode, nface);
1916
1917  //   S E T   N O D E S
1918
1919  for (i=1; i<(int)nodes.size(); i++) {
1920    if (nodes[i].s != 0)  polyhedron.pV[nodes[i].s] = nodes[i].v;
1921  }
1922
1923  //   S E T   F A C E S
1924
1925  int k, v[4], f[4];
1926  for (i=1; i<(int)faces.size(); i++) {
1927    if (faces[i].inew == 0) continue;
1928    v[3] = f[3] = k = 0;
1929    iedge = faces[i].iold;
1930    while (iedge > 0) {
1931      if (k > 3) {
1932        std::cerr
1933          << "BooleanProcessor::createPolyhedron : too many edges"
1934          << std::endl;
1935        break;
1936      }
1937      v[k]  = nodes[edges[iedge].i1].s;
1938      if (edges[iedge].ivis < 0) v[k] = -v[k];
1939      f[k]  = faces[edges[iedge].iface2].inew;
1940      iedge = edges[iedge].inext;
1941      k++;
1942    }
1943    if (k < 3) {
1944      std::cerr
1945        << "BooleanProcessor::createPolyhedron : "
1946        << "face has only " << k << " edges"
1947        << std::endl;
1948    }
1949    polyhedron.pF[faces[i].inew] =
1950      G4Facet(v[0],f[0], v[1],f[1], v[2],f[2], v[3],f[3]);
1951  }
1952  return polyhedron;
1953}
1954
1955int BooleanProcessor::ishift = 0; //G.Barrand
1956int BooleanProcessor::get_shift() { return ishift;} //G.Barrand
1957void BooleanProcessor::set_shift(int a_shift) { ishift = a_shift;} //G.Barrand
1958#define NUM_SHIFT 8
1959int BooleanProcessor::get_num_shift() { return NUM_SHIFT;} //G.Barrand
1960
1961HepPolyhedron BooleanProcessor::execute(int op,
1962                                        const HepPolyhedron & a,
1963                                        const HepPolyhedron & b,
1964                                        int& err) //G.Barrand
1965/***********************************************************************
1966 *                                                                     *
1967 * Name: BooleanProcessor::execute                   Date:    10.12.99 *
1968 * Author: E.Chernyaev                               Revised:          *
1969 *                                                                     *
1970 * Function: Execute boolean operation.                                *
1971 *                                                                     *
1972 ***********************************************************************/
1973{
1974  //static int ishift = 0; //G.Barrand
1975  //static double shift[8][3] = {
1976  static double shift[NUM_SHIFT][3] = { //G.Barrand
1977    {  31,  23,  17},
1978    { -31, -23, -17},
1979    { -23,  17,  31},
1980    {  23, -17, -31},
1981    { -17, -31,  23},
1982    {  17,  31, -23},
1983    {  31, -23,  17},
1984    { -31,  23, -17}
1985  };           
1986
1987/*
1988  std::cerr << "BooleanProcessor::execute : ++++++++++++++++++++++"
1989            << a.getName().getString()
1990            << b.getName().getString()
1991            << std::endl;
1992*/
1993
1994  //   I N I T I A T E   P R O C E S S O R
1995
1996  processor_error = 0;
1997  operation = op;
1998  nodes.clear(); nodes.push_back(CRAZY_POINT);
1999  edges.clear(); edges.push_back(ExtEdge());
2000  faces.clear(); faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ?
2001
2002  //   T A K E   P O L Y H E D R A
2003
2004  ifaces1 = faces.size(); takePolyhedron(a,0,0,0);
2005  ifaces2 = faces.size(); takePolyhedron(b,0,0,0);
2006
2007  if (processor_error) {             // corrapted polyhedron
2008    std::cerr
2009      << "BooleanProcessor: corrapted input polyhedron"
2010      << std::endl;
2011    err = processor_error; //G.Barrand
2012    return HepPolyhedron();
2013  }
2014  if (ifaces1 == ifaces2) {          // a is empty
2015    err = processor_error; //G.Barrand
2016    switch (operation) {
2017    case OP_UNION:
2018      return b;
2019    case OP_INTERSECTION:
2020      std::cerr
2021        << "BooleanProcessor: intersection with empty polyhedron"
2022        << std::endl;
2023      return HepPolyhedron();
2024    case OP_SUBTRACTION:
2025      std::cerr
2026        << "BooleanProcessor: subtraction from empty polyhedron"
2027        << std::endl;
2028      return HepPolyhedron();
2029    }
2030  }
2031  if (ifaces2 == (int)faces.size()) {     // b is empty
2032    err = processor_error; //G.Barrand
2033    switch (operation) {
2034    case OP_UNION:
2035      return a;
2036    case OP_INTERSECTION:
2037      std::cerr
2038        << "BooleanProcessor: intersection with empty polyhedron"
2039        << std::endl;
2040      return HepPolyhedron();
2041    case OP_SUBTRACTION:
2042      return a;
2043    }
2044  }
2045
2046  //   S E T   I N I T I A L   M I N - M A X   A N D   T O L E R A N C E
2047
2048  del = findMinMax();
2049
2050  //   W O R K A R O U N D   T O   A V O I D   I E   A N D   E E
2051         
2052/*
2053#define PROCESSOR_ERROR(a_what) \
2054  std::cerr << "BooleanProcessor: boolean operation problem (" << a_what \
2055            << "). Try again with other shifts."\
2056            << std::endl;
2057*/
2058#define PROCESSOR_ERROR(a_what)
2059
2060  unsigned int try_count = 1;
2061  while(true) { //G.Barrand
2062
2063  double ddxx = del*shift[ishift][0];
2064  double ddyy = del*shift[ishift][1];
2065  double ddzz = del*shift[ishift][2];
2066  ishift++; if (ishift == get_num_shift()) ishift = 0;
2067
2068  processor_error = 0; //G.Barrand
2069  operation = op;
2070  nodes.clear(); nodes.push_back(CRAZY_POINT);
2071  edges.clear(); edges.push_back(ExtEdge());
2072  faces.clear(); faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ?
2073
2074  ifaces1 = faces.size(); takePolyhedron(a,0,0,0);
2075  ifaces2 = faces.size(); takePolyhedron(b,ddxx,ddyy,ddzz);
2076
2077  if (processor_error) { PROCESSOR_ERROR(1) } //G.Barrand
2078
2079  del = findMinMax();
2080
2081  //   P R E S E L E C T   O U T S I D E   F A C E S
2082
2083  iout1 = iout2 = 0;
2084  selectOutsideFaces(ifaces1, iout1);
2085  selectOutsideFaces(ifaces2, iout2);
2086
2087  if (processor_error) { PROCESSOR_ERROR(2) } //G.Barrand
2088
2089  //   P R E S E L E C T   N O   I N T E R S E C T I O N   F A C E S
2090
2091  int ifa1, ifa2;
2092  iunk1 = iunk2 = 0;
2093  if (iout1 != 0 || iout2 != 0) {
2094    for(;;) {
2095      ifa1 = iunk1;
2096      ifa2 = iunk2;
2097      selectOutsideFaces(ifaces1, iunk1);
2098      selectOutsideFaces(ifaces2, iunk2);
2099      if (iunk1 == ifa1 && iunk2 == ifa2) break;
2100      findMinMax();
2101    }
2102  }
2103
2104  if (processor_error) { PROCESSOR_ERROR(3) } //G.Barrand
2105
2106  //   F I N D   N E W   E D G E S
2107
2108  if (ifaces1 != 0 && ifaces2 != 0 ) {
2109    ifa1 = ifaces1;
2110    while (ifa1 > 0) {
2111      ifa2 = ifaces2;
2112      while (ifa2 > 0) {
2113        testFaceVsFace(ifa1, ifa2);
2114        ifa2 = faces[ifa2].inext;
2115      }
2116      ifa1 = faces[ifa1].inext;
2117    }
2118  }
2119  if (processor_error) { PROCESSOR_ERROR(4) } //G.Barrand
2120
2121  //   C O N S T R U C T   N E W   F A C E S
2122
2123  assembleNewFaces((operation == OP_INTERSECTION) ? 1 : 0, ifaces1);
2124  if (processor_error) { PROCESSOR_ERROR(5) } //G.Barrand
2125  assembleNewFaces((operation == OP_UNION) ? 0 : 1, ifaces2);
2126  if (processor_error) { PROCESSOR_ERROR(6) } //G.Barrand
2127
2128  //   A S S E M B L E   S U I T A B L E   F A C E S
2129
2130  initiateLists();
2131  for (;;) {
2132    assemblePolyhedra();
2133    if (unknown_faces.front() != 0) {
2134      processor_error = 1;
2135#ifdef BP_DEBUG
2136      std::cerr
2137        << "BooleanProcessor::execute : unknown faces !!!"
2138        << std::endl;
2139#endif
2140    }
2141    break;
2142  }
2143  if (processor_error) { PROCESSOR_ERROR(7) } //G.Barrand
2144
2145  //   T R I A N G U L A T E   A C C E P T E D   F A C E S
2146
2147  ifa1 = result_faces.front();
2148  while (ifa1 > 0) {
2149    ifa2 = ifa1;
2150    ifa1 = faces[ifa2].inext;
2151    if (faces[ifa2].inew == NEW_FACE) triangulateFace(ifa2);
2152    if (processor_error) {
2153      PROCESSOR_ERROR(8) //G.Barrand
2154      break; //G.Barrand
2155    }
2156  }
2157
2158  if(!processor_error) {   
2159#ifdef BP_DEBUG
2160    if(try_count!=1) {
2161      std::cerr
2162         << "BooleanProcessor::execute : had converged."
2163         << std::endl;
2164    }
2165#endif
2166    break;
2167  }
2168
2169  if((int)try_count>get_num_shift()) {
2170#ifdef BP_DEBUG
2171    std::cerr << "BooleanProcessor: "
2172              << " all shifts tried. Boolean operation (" << op << ") failure."
2173              << " a name \"" << a.getName().getString() << "\""
2174              << " b name \"" << b.getName().getString() << "\""
2175              << std::endl;
2176#endif
2177    err = processor_error;
2178    return a;
2179  }
2180
2181#ifdef BP_DEBUG
2182  std::cerr
2183     << "BooleanProcessor::execute : try another tilt..."
2184     << std::endl;
2185#endif
2186
2187  try_count++;
2188
2189  } //G.Barrand : end while shift.
2190#undef PROCESSOR_ERROR //G.Barrand
2191
2192  //   C R E A T E   P O L Y H E D R O N
2193 
2194  err = processor_error;
2195  return createPolyhedron();
2196}
2197
2198
2199//#include <cfortran.h>
2200//#include <higz.h>
2201//#include "zbuf.h"
2202//void BooleanProcessor::draw()
2203/***********************************************************************
2204 *                                                                     *
2205 * Name: BooleanProcessor::draw                      Date:    10.12.99 *
2206 * Author: E.Chernyaev                               Revised:          *
2207 *                                                                     *
2208 * Function: Draw                                                      *
2209 *                                                                     *
2210 ***********************************************************************/
2211/*
2212{
2213  int II;
2214  int   icol, i1, i2, iedge, iface, ilist[4];
2215  float p1[3], p2[3];
2216
2217  ilist[0] = ifaces1;
2218  ilist[1] = ifaces2;
2219  ilist[2] = iout1;
2220  ilist[3] = iout2;
2221
2222  for (int i=0; i<4; i++) {
2223
2224    if (i == 0) cout << "========= Ifaces_1" << endl;
2225    if (i == 1) cout << "========= Ifaces_2" << endl;
2226    if (i == 2) cout << "========= Iout_1" << endl;
2227    if (i == 3) cout << "========= Iout_2" << endl;
2228
2229    icol = i+1;
2230    iface = ilist[i];
2231    while (iface > 0) {
2232
2233      cout << "iface = " << iface << endl;
2234      cout << "--- iold" << endl;
2235
2236      iedge = faces[iface].iold;
2237      icol = 2;
2238
2239      while (iedge > 0) {
2240
2241        cout << "  iegde = " << iedge
2242             << " i1,i2 =" << edges[iedge].i1 << "," << edges[iedge].i2
2243             << " iface1,iface2 = "
2244             << edges[iedge].iface1 << "," << edges[iedge].iface2
2245             << endl;
2246
2247        i1 = edges[iedge].i1;
2248        p1[0] = nodes[i1].v.x();
2249        p1[1] = nodes[i1].v.y();
2250        p1[2] = nodes[i1].v.z();
2251        IHWTON(p1,p1);
2252        i2 = edges[iedge].i2;
2253        p2[0] = nodes[i2].v.x();
2254        p2[1] = nodes[i2].v.y();
2255        p2[2] = nodes[i2].v.z();
2256        IHWTON(p2,p2);
2257//        icol =  (edges[iedge].ivis > 0) ? 1 : 2;
2258        IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]);
2259        iedge = edges[iedge].inext;
2260      }
2261     
2262      cout << "--- inew" << endl;
2263
2264      iedge = faces[iface].inew;
2265      icol = 3;
2266
2267      while (iedge > 0) {
2268
2269        cout << "  iegde = " << iedge
2270             << " i1,i2 =" << edges[iedge].i1 << "," << edges[iedge].i2
2271             << " iface1,iface2 = "
2272             << edges[iedge].iface1 << "," << edges[iedge].iface2
2273             << endl;
2274
2275        i1 = edges[iedge].i1;
2276        p1[0] = nodes[i1].v.x();
2277        p1[1] = nodes[i1].v.y();
2278        p1[2] = nodes[i1].v.z();
2279        IHWTON(p1,p1);
2280        i2 = edges[iedge].i2;
2281        p2[0] = nodes[i2].v.x();
2282        p2[1] = nodes[i2].v.y();
2283        p2[2] = nodes[i2].v.z();
2284        IHWTON(p2,p2);
2285//        icol =  (edges[iedge].ivis > 0) ? 1 : 2;
2286        IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]);
2287        iedge = edges[iedge].inext;
2288      }
2289      iface = faces[iface].inext;
2290
2291      IHZTOX(0,100,100);
2292      ixupdwi(0);
2293      cin >> II;
2294      ixclrwi();
2295      IHZCLE(0);
2296    }
2297  }
2298}
2299*/
2300
2301/*
2302//--------------------------------------------------------------------
2303void
2304BooleanProcessor::draw_edge(int icol, int iedge) {
2305  int   i1, i2;
2306  float p1[3], p2[3];
2307
2308  i1 = edges[iedge].i1;
2309  p1[0] = nodes[i1].v.x();
2310  p1[1] = nodes[i1].v.y();
2311  p1[2] = nodes[i1].v.z();
2312  IHWTON(p1,p1);
2313  i2 = edges[iedge].i2;
2314  p2[0] = nodes[i2].v.x();
2315  p2[1] = nodes[i2].v.y();
2316  p2[2] = nodes[i2].v.z();
2317  IHWTON(p2,p2);
2318  IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]);
2319}
2320
2321//--------------------------------------------------------------------
2322void
2323BooleanProcessor::draw_contour(int i1col, int i2col, int ihead) {
2324  int iedge, icol;
2325  iedge = ihead;
2326  while (iedge > 0) {
2327    icol = (edges[iedge].ivis > 0) ? i1col : i2col;
2328    draw_edge(icol, iedge);
2329    iedge = edges[iedge].inext;
2330  }
2331
2332  IHZTOX(0,100,100);
2333  ixupdwi(0);
2334
2335  int i;
2336  std::cin >> i;
2337}
2338
2339//--------------------------------------------------------------------
2340void
2341BooleanProcessor::print_face(int iface) {
2342  cout.precision(3);
2343  cout << "\n====== Face N " << iface << endl;
2344  cout << "iedges[4] = "
2345       << faces[iface].iedges[0] << ", "
2346       << faces[iface].iedges[1] << ", "
2347       << faces[iface].iedges[2] << ", "
2348       << faces[iface].iedges[3] << endl;
2349  cout << "rmin[3] = "
2350       << faces[iface].rmin[0] << ", "
2351       << faces[iface].rmin[1] << ", "
2352       << faces[iface].rmin[2] << endl;
2353  cout << "rmax[3] = "
2354       << faces[iface].rmax[0] << ", "
2355       << faces[iface].rmax[1] << ", "
2356       << faces[iface].rmax[2] << endl;
2357  cout << "iprev,inext = "
2358       << faces[iface].iprev << ", "
2359       << faces[iface].inext << endl;
2360  cout << "iold = " << faces[iface].iold << endl;
2361  for(int i = faces[iface].iold; i != 0;) {
2362    print_edge(i);
2363    i = edges[abs(i)].inext;
2364  }
2365
2366  cout << "inew = ";
2367  switch (faces[iface].inew) {
2368  case UNKNOWN_FACE:
2369    cout << "UNKNOWN_FACE" << endl;
2370    break;
2371  case ORIGINAL_FACE:
2372    cout << "ORIGINAL_FACE" << endl;
2373    break;
2374  case NEW_FACE:
2375    cout << "NEW_FACE" << endl;
2376    break;
2377  case UNSUITABLE_FACE:
2378    cout << "UNSUITABLE_FACE" << endl;
2379    break;
2380  case DEFECTIVE_FACE:
2381    cout << "DEFECTIVE_FACE" << endl;
2382    break;
2383  default:
2384    cout << faces[iface].inew << endl;
2385    for(int k = faces[iface].inew; k != 0;) {
2386      print_edge(k);
2387      k = edges[abs(k)].inext;
2388    }
2389  }
2390}
2391
2392//--------------------------------------------------------------------
2393void
2394BooleanProcessor::print_edge(int iedge) {
2395  cout << "==== Edge N " << iedge << endl;
2396  int i = std::abs(iedge);
2397  int i1 = edges[i].i1;
2398  int i2 = edges[i].i2;
2399  cout << "node[" << i1 << "] = "
2400       << nodes[i1].v.x() << ", "
2401       << nodes[i1].v.y() << ", "
2402       << nodes[i1].v.z() << endl;
2403
2404  cout << "node[" << i2 << "] = "
2405       << nodes[i2].v.x() << ", "
2406       << nodes[i2].v.y() << ", "
2407       << nodes[i2].v.z() << endl;
2408
2409  cout << "iface1,iface2,ivis,inext = "
2410       << edges[i].iface1 << ", "
2411       << edges[i].iface2 << ", "
2412       << edges[i].ivis   << ", "
2413       << edges[i].inext  << endl;
2414}
2415*/
2416
2417void BooleanProcessor::dump() {//G.Barrand
2418  unsigned int number = nodes.size();
2419  std::cout << "nodes : " << number << endl;
2420  for(unsigned int index=0;index<number;index++) {
2421    const ExtNode& node = nodes[index];
2422    std::cout << " " << index
2423              << " x = " << node.v[0]
2424              << " y = " << node.v[1]
2425              << " z = " << node.v[2]
2426              << std::endl;
2427  }
2428}
Note: See TracBrowser for help on using the repository browser.