logo

Inkscape

  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

ShapeSweep.cpp

Go to the documentation of this file.
00001 /*
00002  *  ShapeSweep.cpp
00003  *  nlivarot
00004  *
00005  *  Created by fred on Thu Jun 19 2003.
00006  *
00007  */
00008 
00009 #include <cstdio>
00010 #include <cstdlib>
00011 #include <cstring>
00012 #include <glib/gmem.h>
00013 #include "Shape.h"
00014 #include "livarot/sweep-event-queue.h"
00015 #include "livarot/sweep-tree-list.h"
00016 #include "livarot/sweep-tree.h"
00017 
00018 #include "libnr/nr-matrix.h"
00019 
00020 //int   doDebug=0;
00021 
00022 /*
00023  * El Intersector.
00024  * algorithm: 1) benley ottman to get intersections of all the polygon's edges
00025  *            2) rounding of the points of the polygon, Hooby's algorithm
00026  *            3) DFS with clockwise choice of the edge to compute the windings
00027  *            4) choose edges according to winding numbers and fill rule
00028  * some additional nastyness: step 2 needs a seed winding number for the upper-left point of each 
00029  * connex subgraph of the graph. computing these brutally is O(n^3): baaaad. so during the sweeping in 1)
00030  * we keep for each point the edge of the resulting graph (not the original) that lies just on its left; 
00031  * when the time comes for the point to get its winding number computed, that edge must have been treated,
00032  * because its upper end lies above the aforementioned point, meaning we know the winding number of the point.
00033  * only, there is a catch: since we're sweeping the polygon, the edge we want to link the point to has not yet been
00034  * added (that would be too easy...). so the points are put on a linked list on the original shape's edge, and the list
00035  * is flushed when the edge is added.
00036  * rounding: to do the rounding, we need to find which edges cross the surrounding of the rounded points (at 
00037  * each sweepline position). grunt method tries all combination of "rounded points in the sweepline"x"edges crossing 
00038  * the sweepline". That's bad (and that's what polyboolean does, if i am not mistaken). so for each point 
00039  * rounded in a given sweepline, keep immediate left and right edges at the time the point is treated.
00040  * when edges/points crossing are searched, walk the edge list (in the  sweepline at the end of the batch) starting 
00041  * from the rounded points' left and right from that time. may sound strange, but it works because edges that
00042  * end or start in the batch have at least one end in the batch.
00043  * all these are the cause of the numerous linked lists of points and edges maintained in the sweeping
00044  */
00045 
00046 void
00047 Shape::ResetSweep (void)
00048 {
00049   MakePointData (true);
00050   MakeEdgeData (true);
00051   MakeSweepSrcData (true);
00052 }
00053 
00054 void
00055 Shape::CleanupSweep (void)
00056 {
00057   MakePointData (false);
00058   MakeEdgeData (false);
00059   MakeSweepSrcData (false);
00060 }
00061 
00062 void
00063 Shape::ForceToPolygon (void)
00064 {
00065   type = shape_polygon;
00066 }
00067 
00068 int
00069 Shape::Reoriente (Shape * a)
00070 {
00071   Reset (0, 0);
00072   if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1)
00073     return 0;
00074   if (directedEulerian(a) == false)
00075     return shape_input_err;
00076 
00077   _pts = a->_pts;
00078   if (numberOfPoints() > maxPt)
00079     {
00080       maxPt = numberOfPoints();
00081       if (_has_points_data) {
00082         pData.resize(maxPt);
00083         _point_data_initialised = false;
00084         _bbox_up_to_date = false;
00085         }
00086     }
00087 
00088   _aretes = a->_aretes;
00089   if (numberOfEdges() > maxAr)
00090     {
00091       maxAr = numberOfEdges();
00092       if (_has_edges_data)
00093     eData.resize(maxAr);
00094       if (_has_sweep_src_data)
00095     swsData.resize(maxAr);
00096       if (_has_sweep_dest_data)
00097     swdData.resize(maxAr);
00098       if (_has_raster_data)
00099     swrData.resize(maxAr);
00100     }
00101 
00102   MakePointData (true);
00103   MakeEdgeData (true);
00104   MakeSweepDestData (true);
00105 
00106   initialisePointData();
00107 
00108   for (int i = 0; i < numberOfPoints(); i++) {
00109       _pts[i].x = pData[i].rx;
00110       _pts[i].oldDegree = getPoint(i).totalDegree();
00111   }
00112   
00113   for (int i = 0; i < a->numberOfEdges(); i++)
00114     {
00115       eData[i].rdx = pData[getEdge(i).en].rx - pData[getEdge(i).st].rx;
00116       eData[i].weight = 1;
00117       _aretes[i].dx = eData[i].rdx;
00118     }
00119 
00120   SortPointsRounded ();
00121 
00122   _need_edges_sorting = true;
00123   GetWindings (this, NULL, bool_op_union, true);
00124 
00125 //      Plot(341,56,8,400,400,true,true,false,true);
00126   for (int i = 0; i < numberOfEdges(); i++)
00127     {
00128       swdData[i].leW %= 2;
00129       swdData[i].riW %= 2;
00130       if (swdData[i].leW < 0)
00131     swdData[i].leW = -swdData[i].leW;
00132       if (swdData[i].riW < 0)
00133     swdData[i].riW = -swdData[i].riW;
00134       if (swdData[i].leW > 0 && swdData[i].riW <= 0)
00135     {
00136       eData[i].weight = 1;
00137     }
00138       else if (swdData[i].leW <= 0 && swdData[i].riW > 0)
00139     {
00140       Inverse (i);
00141       eData[i].weight = 1;
00142     }
00143       else
00144     {
00145       eData[i].weight = 0;
00146       SubEdge (i);
00147       i--;
00148     }
00149     }
00150 
00151   MakePointData (false);
00152   MakeEdgeData (false);
00153   MakeSweepDestData (false);
00154 
00155   if (directedEulerian(this) == false)
00156     {
00157 //              printf( "pas euclidian2");
00158       _pts.clear();
00159       _aretes.clear();
00160       return shape_euler_err;
00161     }
00162 
00163   type = shape_polygon;
00164   return 0;
00165 }
00166 
00167 int
00168 Shape::ConvertToShape (Shape * a, FillRule directed, bool invert)
00169 {
00170     Reset (0, 0);
00171 
00172     if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1) {
00173     return 0;
00174     }
00175     
00176     if ( directed != fill_justDont && directedEulerian(a) == false ) {
00177             g_warning ("Shape error in ConvertToShape: directedEulerian(a) == false\n");
00178                 return shape_input_err;
00179     }
00180   
00181     a->ResetSweep();
00182 
00183     if (sTree == NULL) {
00184     sTree = new SweepTreeList(a->numberOfEdges());
00185     }
00186     if (sEvts == NULL) {
00187     sEvts = new SweepEventQueue(a->numberOfEdges());
00188     }
00189   
00190     MakePointData(true);
00191     MakeEdgeData(true);
00192     MakeSweepSrcData(true);
00193     MakeSweepDestData(true);
00194     MakeBackData(a->_has_back_data);
00195 
00196     a->initialisePointData();
00197     a->initialiseEdgeData();
00198 
00199     a->SortPointsRounded();
00200 
00201     chgts.clear();
00202 
00203     double lastChange = a->pData[0].rx[1] - 1.0;
00204     int lastChgtPt = 0;
00205     int edgeHead = -1;
00206     Shape *shapeHead = NULL;
00207 
00208     clearIncidenceData();
00209     
00210     int curAPt = 0;
00211 
00212     while (curAPt < a->numberOfPoints() || sEvts->size() > 0) {
00213     Geom::Point ptX;
00214       double ptL, ptR;
00215       SweepTree *intersL = NULL;
00216       SweepTree *intersR = NULL;
00217       int nPt = -1;
00218       Shape *ptSh = NULL;
00219       bool isIntersection = false;
00220       if (sEvts->peek(intersL, intersR, ptX, ptL, ptR))
00221     {
00222       if (a->pData[curAPt].pending > 0
00223           || (a->pData[curAPt].rx[1] > ptX[1]
00224           || (a->pData[curAPt].rx[1] == ptX[1]
00225               && a->pData[curAPt].rx[0] > ptX[0])))
00226         {
00227           /* FIXME: could just be pop? */
00228           sEvts->extract(intersL, intersR, ptX, ptL, ptR);
00229           isIntersection = true;
00230         }
00231       else
00232         {
00233           nPt = curAPt++;
00234           ptSh = a;
00235           ptX = ptSh->pData[nPt].rx;
00236           isIntersection = false;
00237         }
00238     }
00239       else
00240     {
00241       nPt = curAPt++;
00242       ptSh = a;
00243       ptX = ptSh->pData[nPt].rx;
00244       isIntersection = false;
00245     }
00246 
00247       if (isIntersection == false)
00248     {
00249       if (ptSh->getPoint(nPt).dI == 0 && ptSh->getPoint(nPt).dO == 0)
00250         continue;
00251     }
00252 
00253       Geom::Point rPtX;
00254       rPtX[0]= Round (ptX[0]);
00255       rPtX[1]= Round (ptX[1]);
00256       int lastPointNo = -1;
00257       lastPointNo = AddPoint (rPtX);
00258       pData[lastPointNo].rx = rPtX;
00259 
00260       if (rPtX[1] > lastChange)
00261     {
00262       int lastI = AssemblePoints (lastChgtPt, lastPointNo);
00263 
00264       Shape *curSh = shapeHead;
00265       int curBo = edgeHead;
00266       while (curSh)
00267         {
00268           curSh->swsData[curBo].leftRnd =
00269         pData[curSh->swsData[curBo].leftRnd].newInd;
00270           curSh->swsData[curBo].rightRnd =
00271         pData[curSh->swsData[curBo].rightRnd].newInd;
00272 
00273           Shape *neSh = curSh->swsData[curBo].nextSh;
00274           curBo = curSh->swsData[curBo].nextBo;
00275           curSh = neSh;
00276         }
00277 
00278       for (unsigned int i = 0; i < chgts.size(); i++)
00279         {
00280           chgts[i].ptNo = pData[chgts[i].ptNo].newInd;
00281           if (chgts[i].type == 0)
00282         {
00283           if (chgts[i].src->getEdge(chgts[i].bord).st <
00284               chgts[i].src->getEdge(chgts[i].bord).en)
00285             {
00286               chgts[i].src->swsData[chgts[i].bord].stPt =
00287             chgts[i].ptNo;
00288             }
00289           else
00290             {
00291               chgts[i].src->swsData[chgts[i].bord].enPt =
00292             chgts[i].ptNo;
00293             }
00294         }
00295           else if (chgts[i].type == 1)
00296         {
00297           if (chgts[i].src->getEdge(chgts[i].bord).st >
00298               chgts[i].src->getEdge(chgts[i].bord).en)
00299             {
00300               chgts[i].src->swsData[chgts[i].bord].stPt =
00301             chgts[i].ptNo;
00302             }
00303           else
00304             {
00305               chgts[i].src->swsData[chgts[i].bord].enPt =
00306             chgts[i].ptNo;
00307             }
00308         }
00309         }
00310 
00311       CheckAdjacencies (lastI, lastChgtPt, shapeHead, edgeHead);
00312 
00313       CheckEdges (lastI, lastChgtPt, a, NULL, bool_op_union);
00314 
00315       for (int i = lastChgtPt; i < lastI; i++) {
00316         if (pData[i].askForWindingS) {
00317             Shape *windS = pData[i].askForWindingS;
00318             int windB = pData[i].askForWindingB;
00319             pData[i].nextLinkedPoint = windS->swsData[windB].firstLinkedPoint;
00320             windS->swsData[windB].firstLinkedPoint = i;
00321           }
00322        }
00323 
00324     if (lastI < lastPointNo) {
00325           _pts[lastI] = getPoint(lastPointNo);
00326        pData[lastI] = pData[lastPointNo];
00327       }
00328       lastPointNo = lastI;
00329       _pts.resize(lastI + 1);
00330 
00331       lastChgtPt = lastPointNo;
00332       lastChange = rPtX[1];
00333       chgts.clear();
00334       edgeHead = -1;
00335       shapeHead = NULL;
00336     }
00337 
00338 
00339       if (isIntersection)
00340     {
00341 //                      printf("(%i %i [%i %i]) ",intersL->bord,intersR->bord,intersL->startPoint,intersR->startPoint);
00342       intersL->RemoveEvent (*sEvts, LEFT);
00343       intersR->RemoveEvent (*sEvts, RIGHT);
00344 
00345       AddChgt (lastPointNo, lastChgtPt, shapeHead, edgeHead, INTERSECTION,
00346            intersL->src, intersL->bord, intersR->src, intersR->bord);
00347 
00348       intersL->SwapWithRight (*sTree, *sEvts);
00349 
00350       TesteIntersection (intersL, LEFT, false);
00351       TesteIntersection (intersR, RIGHT, false);
00352     }
00353       else
00354     {
00355       int cb;
00356 
00357       int nbUp = 0, nbDn = 0;
00358       int upNo = -1, dnNo = -1;
00359       cb = ptSh->getPoint(nPt).incidentEdge[FIRST];
00360       while (cb >= 0 && cb < ptSh->numberOfEdges())
00361         {
00362           if ((ptSh->getEdge(cb).st < ptSh->getEdge(cb).en
00363            && nPt == ptSh->getEdge(cb).en)
00364           || (ptSh->getEdge(cb).st > ptSh->getEdge(cb).en
00365               && nPt == ptSh->getEdge(cb).st))
00366         {
00367           upNo = cb;
00368           nbUp++;
00369         }
00370           if ((ptSh->getEdge(cb).st > ptSh->getEdge(cb).en
00371            && nPt == ptSh->getEdge(cb).en)
00372           || (ptSh->getEdge(cb).st < ptSh->getEdge(cb).en
00373               && nPt == ptSh->getEdge(cb).st))
00374         {
00375           dnNo = cb;
00376           nbDn++;
00377         }
00378           cb = ptSh->NextAt (nPt, cb);
00379         }
00380 
00381       if (nbDn <= 0)
00382         {
00383           upNo = -1;
00384         }
00385       if (upNo >= 0 && (SweepTree *) ptSh->swsData[upNo].misc == NULL)
00386         {
00387           upNo = -1;
00388         }
00389 
00390       bool doWinding = true;
00391 
00392       if (nbUp > 0)
00393         {
00394           cb = ptSh->getPoint(nPt).incidentEdge[FIRST];
00395           while (cb >= 0 && cb < ptSh->numberOfEdges())
00396         {
00397           if ((ptSh->getEdge(cb).st < ptSh->getEdge(cb).en
00398                && nPt == ptSh->getEdge(cb).en)
00399               || (ptSh->getEdge(cb).st > ptSh->getEdge(cb).en
00400               && nPt == ptSh->getEdge(cb).st))
00401             {
00402               if (cb != upNo)
00403             {
00404               SweepTree *node =
00405                 (SweepTree *) ptSh->swsData[cb].misc;
00406               if (node == NULL)
00407                 {
00408                 }
00409               else
00410                 {
00411                   AddChgt (lastPointNo, lastChgtPt, shapeHead,
00412                        edgeHead, EDGE_REMOVED, node->src, node->bord,
00413                        NULL, -1);
00414                   ptSh->swsData[cb].misc = NULL;
00415 
00416                   int onLeftB = -1, onRightB = -1;
00417                   Shape *onLeftS = NULL;
00418                   Shape *onRightS = NULL;
00419                   if (node->elem[LEFT])
00420                 {
00421                   onLeftB =
00422                     (static_cast <
00423                      SweepTree * >(node->elem[LEFT]))->bord;
00424                   onLeftS =
00425                     (static_cast <
00426                      SweepTree * >(node->elem[LEFT]))->src;
00427                 }
00428                   if (node->elem[RIGHT])
00429                 {
00430                   onRightB =
00431                     (static_cast <
00432                      SweepTree * >(node->elem[RIGHT]))->bord;
00433                   onRightS =
00434                     (static_cast <
00435                      SweepTree * >(node->elem[RIGHT]))->src;
00436                 }
00437 
00438                   node->Remove (*sTree, *sEvts, true);
00439                   if (onLeftS && onRightS)
00440                 {
00441                   SweepTree *onLeft =
00442                     (SweepTree *) onLeftS->swsData[onLeftB].
00443                     misc;
00444                   if (onLeftS == ptSh
00445                       && (onLeftS->getEdge(onLeftB).en == nPt
00446                       || onLeftS->getEdge(onLeftB).st ==
00447                       nPt))
00448                     {
00449                     }
00450                   else
00451                     {
00452                       if (onRightS == ptSh
00453                       && (onRightS->getEdge(onRightB).en ==
00454                           nPt
00455                           || onRightS->getEdge(onRightB).
00456                           st == nPt))
00457                     {
00458                     }
00459                       else
00460                     {
00461                       TesteIntersection (onLeft, RIGHT, false);
00462                     }
00463                     }
00464                 }
00465                 }
00466             }
00467             }
00468           cb = ptSh->NextAt (nPt, cb);
00469         }
00470         }
00471 
00472       // traitement du "upNo devient dnNo"
00473       SweepTree *insertionNode = NULL;
00474       if (dnNo >= 0)
00475         {
00476           if (upNo >= 0)
00477         {
00478           SweepTree *node = (SweepTree *) ptSh->swsData[upNo].misc;
00479 
00480           AddChgt (lastPointNo, lastChgtPt, shapeHead, edgeHead, EDGE_REMOVED,
00481                node->src, node->bord, NULL, -1);
00482 
00483           ptSh->swsData[upNo].misc = NULL;
00484 
00485           node->RemoveEvents (*sEvts);
00486           node->ConvertTo (ptSh, dnNo, 1, lastPointNo);
00487           ptSh->swsData[dnNo].misc = node;
00488           TesteIntersection (node, RIGHT, false);
00489           TesteIntersection (node, LEFT, false);
00490           insertionNode = node;
00491 
00492           ptSh->swsData[dnNo].curPoint = lastPointNo;
00493           AddChgt (lastPointNo, lastChgtPt, shapeHead, edgeHead, EDGE_INSERTED,
00494                node->src, node->bord, NULL, -1);
00495         }
00496           else
00497         {
00498           SweepTree *node = sTree->add(ptSh, dnNo, 1, lastPointNo, this);
00499           ptSh->swsData[dnNo].misc = node;
00500           node->Insert (*sTree, *sEvts, this, lastPointNo, true);
00501           if (doWinding)
00502             {
00503               SweepTree *myLeft =
00504             static_cast < SweepTree * >(node->elem[LEFT]);
00505               if (myLeft)
00506             {
00507               pData[lastPointNo].askForWindingS = myLeft->src;
00508               pData[lastPointNo].askForWindingB = myLeft->bord;
00509             }
00510               else
00511             {
00512               pData[lastPointNo].askForWindingB = -1;
00513             }
00514               doWinding = false;
00515             }
00516           TesteIntersection (node, RIGHT, false);
00517           TesteIntersection (node, LEFT, false);
00518           insertionNode = node;
00519 
00520           ptSh->swsData[dnNo].curPoint = lastPointNo;
00521           AddChgt (lastPointNo, lastChgtPt, shapeHead, edgeHead, EDGE_INSERTED,
00522                node->src, node->bord, NULL, -1);
00523         }
00524         }
00525 
00526       if (nbDn > 1)
00527         {           // si nbDn == 1 , alors dnNo a deja ete traite
00528           cb = ptSh->getPoint(nPt).incidentEdge[FIRST];
00529           while (cb >= 0 && cb < ptSh->numberOfEdges())
00530         {
00531           if ((ptSh->getEdge(cb).st > ptSh->getEdge(cb).en
00532                && nPt == ptSh->getEdge(cb).en)
00533               || (ptSh->getEdge(cb).st < ptSh->getEdge(cb).en
00534               && nPt == ptSh->getEdge(cb).st))
00535             {
00536               if (cb != dnNo)
00537             {
00538               SweepTree *node = sTree->add(ptSh, cb, 1, lastPointNo, this);
00539               ptSh->swsData[cb].misc = node;
00540               node->InsertAt (*sTree, *sEvts, this, insertionNode,
00541                       nPt, true);
00542               if (doWinding)
00543                 {
00544                   SweepTree *myLeft =
00545                 static_cast < SweepTree * >(node->elem[LEFT]);
00546                   if (myLeft)
00547                 {
00548                   pData[lastPointNo].askForWindingS =
00549                     myLeft->src;
00550                   pData[lastPointNo].askForWindingB =
00551                     myLeft->bord;
00552                 }
00553                   else
00554                 {
00555                   pData[lastPointNo].askForWindingB = -1;
00556                 }
00557                   doWinding = false;
00558                 }
00559               TesteIntersection (node, RIGHT, false);
00560               TesteIntersection (node, LEFT, false);
00561 
00562               ptSh->swsData[cb].curPoint = lastPointNo;
00563               AddChgt (lastPointNo, lastChgtPt, shapeHead,
00564                    edgeHead, EDGE_INSERTED, node->src, node->bord, NULL,
00565                    -1);
00566             }
00567             }
00568           cb = ptSh->NextAt (nPt, cb);
00569         }
00570         }
00571     }
00572     }
00573   {
00574     int lastI = AssemblePoints (lastChgtPt, numberOfPoints());
00575 
00576 
00577     Shape *curSh = shapeHead;
00578     int curBo = edgeHead;
00579     while (curSh)
00580       {
00581     curSh->swsData[curBo].leftRnd =
00582       pData[curSh->swsData[curBo].leftRnd].newInd;
00583     curSh->swsData[curBo].rightRnd =
00584       pData[curSh->swsData[curBo].rightRnd].newInd;
00585 
00586     Shape *neSh = curSh->swsData[curBo].nextSh;
00587     curBo = curSh->swsData[curBo].nextBo;
00588     curSh = neSh;
00589       }
00590 
00591     for (unsigned int i = 0; i < chgts.size(); i++)
00592       {
00593     chgts[i].ptNo = pData[chgts[i].ptNo].newInd;
00594     if (chgts[i].type == 0)
00595       {
00596         if (chgts[i].src->getEdge(chgts[i].bord).st <
00597         chgts[i].src->getEdge(chgts[i].bord).en)
00598           {
00599         chgts[i].src->swsData[chgts[i].bord].stPt = chgts[i].ptNo;
00600           }
00601         else
00602           {
00603         chgts[i].src->swsData[chgts[i].bord].enPt = chgts[i].ptNo;
00604           }
00605       }
00606     else if (chgts[i].type == 1)
00607       {
00608         if (chgts[i].src->getEdge(chgts[i].bord).st >
00609         chgts[i].src->getEdge(chgts[i].bord).en)
00610           {
00611         chgts[i].src->swsData[chgts[i].bord].stPt = chgts[i].ptNo;
00612           }
00613         else
00614           {
00615         chgts[i].src->swsData[chgts[i].bord].enPt = chgts[i].ptNo;
00616           }
00617       }
00618       }
00619 
00620     CheckAdjacencies (lastI, lastChgtPt, shapeHead, edgeHead);
00621 
00622     CheckEdges (lastI, lastChgtPt, a, NULL, bool_op_union);
00623 
00624     for (int i = lastChgtPt; i < lastI; i++)
00625       {
00626     if (pData[i].askForWindingS)
00627       {
00628         Shape *windS = pData[i].askForWindingS;
00629         int windB = pData[i].askForWindingB;
00630         pData[i].nextLinkedPoint = windS->swsData[windB].firstLinkedPoint;
00631         windS->swsData[windB].firstLinkedPoint = i;
00632       }
00633       }
00634 
00635     _pts.resize(lastI);
00636 
00637     edgeHead = -1;
00638     shapeHead = NULL;
00639   }
00640 
00641     chgts.clear();
00642 
00643 //  Plot (98.0, 112.0, 8.0, 400.0, 400.0, true, true, true, true);
00644 //      Plot(200.0,200.0,2.0,400.0,400.0,true,true,true,true);
00645 
00646   //      AssemblePoints(a);
00647 
00648 //      GetAdjacencies(a);
00649 
00650 //      MakeAretes(a);
00651     clearIncidenceData();
00652 
00653   AssembleAretes (directed);
00654 
00655 //  Plot (98.0, 112.0, 8.0, 400.0, 400.0, true, true, true, true);
00656 
00657   for (int i = 0; i < numberOfPoints(); i++)
00658     {
00659       _pts[i].oldDegree = getPoint(i).totalDegree();
00660     }
00661 //      Validate();
00662 
00663   _need_edges_sorting = true;
00664   if ( directed == fill_justDont ) {
00665     SortEdges();
00666   } else {
00667     GetWindings (a);
00668   }
00669 //  Plot (98.0, 112.0, 8.0, 400.0, 400.0, true, true, true, true);
00670 //   if ( doDebug ) {
00671 //   a->CalcBBox();
00672 //     a->Plot(a->leftX,a->topY,32.0,0.0,0.0,true,true,true,true,"orig.svg");
00673 //     Plot(a->leftX,a->topY,32.0,0.0,0.0,true,true,true,true,"winded.svg");
00674 //   }
00675   if (directed == fill_positive)
00676   {
00677     if (invert)
00678     {
00679       for (int i = 0; i < numberOfEdges(); i++)
00680         {
00681           if (swdData[i].leW < 0 && swdData[i].riW >= 0)
00682         {
00683           eData[i].weight = 1;
00684         }
00685           else if (swdData[i].leW >= 0 && swdData[i].riW < 0)
00686         {
00687           Inverse (i);
00688           eData[i].weight = 1;
00689         }
00690           else
00691         {
00692           eData[i].weight = 0;
00693           SubEdge (i);
00694           i--;
00695         }
00696         }
00697     }
00698     else
00699     {
00700       for (int i = 0; i < numberOfEdges(); i++)
00701         {
00702           if (swdData[i].leW > 0 && swdData[i].riW <= 0)
00703         {
00704           eData[i].weight = 1;
00705         }
00706           else if (swdData[i].leW <= 0 && swdData[i].riW > 0)
00707         {
00708           Inverse (i);
00709           eData[i].weight = 1;
00710         }
00711           else
00712         {
00713            eData[i].weight = 0;
00714           SubEdge (i);
00715           i--;
00716         }
00717         }
00718     }
00719   }
00720   else if (directed == fill_nonZero)
00721   {
00722     if (invert)
00723     {
00724       for (int i = 0; i < numberOfEdges(); i++)
00725         {
00726           if (swdData[i].leW < 0 && swdData[i].riW == 0)
00727         {
00728           eData[i].weight = 1;
00729         }
00730           else if (swdData[i].leW > 0 && swdData[i].riW == 0)
00731         {
00732           eData[i].weight = 1;
00733         }
00734           else if (swdData[i].leW == 0 && swdData[i].riW < 0)
00735         {
00736           Inverse (i);
00737           eData[i].weight = 1;
00738         }
00739           else if (swdData[i].leW == 0 && swdData[i].riW > 0)
00740         {
00741           Inverse (i);
00742           eData[i].weight = 1;
00743         }
00744           else
00745         {
00746           eData[i].weight = 0;
00747           SubEdge (i);
00748           i--;
00749         }
00750         }
00751     }
00752     else
00753     {
00754       for (int i = 0; i < numberOfEdges(); i++)
00755         {
00756           if (swdData[i].leW > 0 && swdData[i].riW == 0)
00757         {
00758           eData[i].weight = 1;
00759         }
00760           else if (swdData[i].leW < 0 && swdData[i].riW == 0)
00761         {
00762           eData[i].weight = 1;
00763         }
00764           else if (swdData[i].leW == 0 && swdData[i].riW > 0)
00765         {
00766           Inverse (i);
00767           eData[i].weight = 1;
00768         }
00769           else if (swdData[i].leW == 0 && swdData[i].riW < 0)
00770         {
00771           Inverse (i);
00772           eData[i].weight = 1;
00773         }
00774           else
00775         {
00776           eData[i].weight = 0;
00777           SubEdge (i);
00778           i--;
00779         }
00780         }
00781     }
00782   }
00783   else if (directed == fill_oddEven)
00784   {
00785     for (int i = 0; i < numberOfEdges(); i++)
00786     {
00787       swdData[i].leW %= 2;
00788       swdData[i].riW %= 2;
00789       if (swdData[i].leW < 0)
00790         swdData[i].leW = -swdData[i].leW;
00791       if (swdData[i].riW < 0)
00792         swdData[i].riW = -swdData[i].riW;
00793       if (swdData[i].leW > 0 && swdData[i].riW <= 0)
00794         {
00795           eData[i].weight = 1;
00796         }
00797       else if (swdData[i].leW <= 0 && swdData[i].riW > 0)
00798         {
00799           Inverse (i);
00800           eData[i].weight = 1;
00801         }
00802       else
00803         {
00804           eData[i].weight = 0;
00805           SubEdge (i);
00806           i--;
00807         }
00808     }
00809   } else if ( directed == fill_justDont ) {
00810     for (int i=0;i<numberOfEdges();i++) {
00811       if ( getEdge(i).st < 0 || getEdge(i).en < 0 ) {
00812         SubEdge(i);
00813         i--;
00814       } else {
00815           eData[i].weight = 0;
00816       }
00817     }
00818   }
00819   
00820 //      Plot(200.0,200.0,2.0,400.0,400.0,true,true,true,true);
00821 
00822   delete sTree;
00823   sTree = NULL;
00824   delete sEvts;
00825   sEvts = NULL;
00826 
00827   MakePointData (false);
00828   MakeEdgeData (false);
00829   MakeSweepSrcData (false);
00830   MakeSweepDestData (false);
00831   a->CleanupSweep ();
00832   type = shape_polygon;
00833   return 0;
00834 }
00835 
00836 // technically it's just a ConvertToShape() on 2 polygons at the same time, and different rules
00837 // for choosing the edges according to their winding numbers.
00838 // probably one of the biggest function i ever wrote.
00839 int
00840 Shape::Booleen (Shape * a, Shape * b, BooleanOp mod,int cutPathID)
00841 {
00842   if (a == b || a == NULL || b == NULL)
00843     return shape_input_err;
00844   Reset (0, 0);
00845   if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1)
00846     return 0;
00847   if (b->numberOfPoints() <= 1 || b->numberOfEdges() <= 1)
00848     return 0;
00849   if ( mod == bool_op_cut ) {
00850   } else if ( mod == bool_op_slice ) {
00851   } else {
00852     if (a->type != shape_polygon)
00853       return shape_input_err;
00854     if (b->type != shape_polygon)
00855       return shape_input_err;
00856   }
00857 
00858   a->ResetSweep ();
00859   b->ResetSweep ();
00860 
00861   if (sTree == NULL) {
00862       sTree = new SweepTreeList(a->numberOfEdges() + b->numberOfEdges());
00863   }
00864   if (sEvts == NULL) {
00865       sEvts = new SweepEventQueue(a->numberOfEdges() + b->numberOfEdges());
00866   }
00867   
00868   MakePointData (true);
00869   MakeEdgeData (true);
00870   MakeSweepSrcData (true);
00871   MakeSweepDestData (true);
00872   if (a->hasBackData () && b->hasBackData ())
00873     {
00874       MakeBackData (true);
00875     }
00876   else
00877     {
00878       MakeBackData (false);
00879     }
00880 
00881   a->initialisePointData();
00882   b->initialisePointData();
00883 
00884   a->initialiseEdgeData();
00885   b->initialiseEdgeData();
00886 
00887   a->SortPointsRounded ();
00888   b->SortPointsRounded ();
00889 
00890   chgts.clear();
00891 
00892   double lastChange =
00893     (a->pData[0].rx[1] <
00894      b->pData[0].rx[1]) ? a->pData[0].rx[1] - 1.0 : b->pData[0].rx[1] - 1.0;
00895   int lastChgtPt = 0;
00896   int edgeHead = -1;
00897   Shape *shapeHead = NULL;
00898 
00899   clearIncidenceData();
00900 
00901   int curAPt = 0;
00902   int curBPt = 0;
00903 
00904   while (curAPt < a->numberOfPoints() || curBPt < b->numberOfPoints() || sEvts->size() > 0)
00905     {
00906 /*      for (int i=0;i<sEvts.nbEvt;i++) {
00907             printf("%f %f %i %i\n",sEvts.events[i].posx,sEvts.events[i].posy,sEvts.events[i].leftSweep->bord,sEvts.events[i].rightSweep->bord); // localizing ok
00908         }
00909         //      cout << endl;
00910         if ( sTree.racine ) {
00911             SweepTree*  ct=static_cast <SweepTree*> (sTree.racine->Leftmost());
00912             while ( ct ) {
00913                 printf("%i %i [%i\n",ct->bord,ct->startPoint,(ct->src==a)?1:0);
00914                 ct=static_cast <SweepTree*> (ct->elem[RIGHT]);
00915             }
00916         }
00917         printf("\n");*/
00918 
00919     Geom::Point ptX;
00920       double ptL, ptR;
00921       SweepTree *intersL = NULL;
00922       SweepTree *intersR = NULL;
00923       int nPt = -1;
00924       Shape *ptSh = NULL;
00925       bool isIntersection = false;
00926 
00927       if (sEvts->peek(intersL, intersR, ptX, ptL, ptR))
00928     {
00929       if (curAPt < a->numberOfPoints())
00930         {
00931           if (curBPt < b->numberOfPoints())
00932         {
00933           if (a->pData[curAPt].rx[1] < b->pData[curBPt].rx[1]
00934               || (a->pData[curAPt].rx[1] == b->pData[curBPt].rx[1]
00935               && a->pData[curAPt].rx[0] < b->pData[curBPt].rx[0]))
00936             {
00937               if (a->pData[curAPt].pending > 0
00938               || (a->pData[curAPt].rx[1] > ptX[1]
00939                   || (a->pData[curAPt].rx[1] == ptX[1]
00940                   && a->pData[curAPt].rx[0] > ptX[0])))
00941             {
00942               /* FIXME: could be pop? */
00943               sEvts->extract(intersL, intersR, ptX, ptL, ptR);
00944               isIntersection = true;
00945             }
00946               else
00947             {
00948               nPt = curAPt++;
00949               ptSh = a;
00950               ptX = ptSh->pData[nPt].rx;
00951               isIntersection = false;
00952             }
00953             }
00954           else
00955             {
00956               if (b->pData[curBPt].pending > 0
00957               || (b->pData[curBPt].rx[1] > ptX[1]
00958                   || (b->pData[curBPt].rx[1] == ptX[1]
00959                   && b->pData[curBPt].rx[0] > ptX[0])))
00960             {
00961               /* FIXME: could be pop? */
00962               sEvts->extract(intersL, intersR, ptX, ptL, ptR);
00963               isIntersection = true;
00964             }
00965               else
00966             {
00967               nPt = curBPt++;
00968               ptSh = b;
00969               ptX = ptSh->pData[nPt].rx;
00970               isIntersection = false;
00971             }
00972             }
00973         }
00974           else
00975         {
00976           if (a->pData[curAPt].pending > 0
00977               || (a->pData[curAPt].rx[1] > ptX[1]
00978               || (a->pData[curAPt].rx[1] == ptX[1]
00979                   && a->pData[curAPt].rx[0] > ptX[0])))
00980             {
00981               /* FIXME: could be pop? */
00982               sEvts->extract(intersL, intersR, ptX, ptL, ptR);
00983               isIntersection = true;
00984             }
00985           else
00986             {
00987               nPt = curAPt++;
00988               ptSh = a;
00989               ptX = ptSh->pData[nPt].rx;
00990               isIntersection = false;
00991             }
00992         }
00993         }
00994       else
00995         {
00996           if (b->pData[curBPt].pending > 0
00997           || (b->pData[curBPt].rx[1] > ptX[1]
00998               || (b->pData[curBPt].rx[1] == ptX[1]
00999               && b->pData[curBPt].rx[0] > ptX[0])))
01000         {
01001           /* FIXME: could be pop? */
01002           sEvts->extract(intersL, intersR, ptX,  ptL, ptR);
01003           isIntersection = true;
01004         }
01005           else
01006         {
01007           nPt = curBPt++;
01008           ptSh = b;
01009           ptX = ptSh->pData[nPt].rx;
01010           isIntersection = false;
01011         }
01012         }
01013     }
01014       else
01015     {
01016       if (curAPt < a->numberOfPoints())
01017         {
01018           if (curBPt < b->numberOfPoints())
01019         {
01020           if (a->pData[curAPt].rx[1] < b->pData[curBPt].rx[1]
01021               || (a->pData[curAPt].rx[1] == b->pData[curBPt].rx[1]
01022               && a->pData[curAPt].rx[0] < b->pData[curBPt].rx[0]))
01023             {
01024               nPt = curAPt++;
01025               ptSh = a;
01026             }
01027           else
01028             {
01029               nPt = curBPt++;
01030               ptSh = b;
01031             }
01032         }
01033           else
01034         {
01035           nPt = curAPt++;
01036           ptSh = a;
01037         }
01038         }
01039       else
01040         {
01041           nPt = curBPt++;
01042           ptSh = b;
01043         }
01044       ptX = ptSh->pData[nPt].rx;
01045       isIntersection = false;
01046     }
01047 
01048       if (isIntersection == false)
01049     {
01050       if (ptSh->getPoint(nPt).dI == 0 && ptSh->getPoint(nPt).dO == 0)
01051         continue;
01052     }
01053 
01054       Geom::Point rPtX;
01055       rPtX[0]= Round (ptX[0]);
01056       rPtX[1]= Round (ptX[1]);
01057       int lastPointNo = -1;
01058       lastPointNo = AddPoint (rPtX);
01059       pData[lastPointNo].rx = rPtX;
01060 
01061       if (rPtX[1] > lastChange)
01062     {
01063       int lastI = AssemblePoints (lastChgtPt, lastPointNo);
01064 
01065 
01066       Shape *curSh = shapeHead;
01067       int curBo = edgeHead;
01068       while (curSh)
01069         {
01070           curSh->swsData[curBo].leftRnd =
01071         pData[curSh->swsData[curBo].leftRnd].newInd;
01072           curSh->swsData[curBo].rightRnd =
01073         pData[curSh->swsData[curBo].rightRnd].newInd;
01074 
01075           Shape *neSh = curSh->swsData[curBo].nextSh;
01076           curBo = curSh->swsData[curBo].nextBo;
01077           curSh = neSh;
01078         }
01079 
01080       for (unsigned int i = 0; i < chgts.size(); i++)
01081         {
01082           chgts[i].ptNo = pData[chgts[i].ptNo].newInd;
01083           if (chgts[i].type == 0)
01084         {
01085           if (chgts[i].src->getEdge(chgts[i].bord).st <
01086               chgts[i].src->getEdge(chgts[i].bord).en)
01087             {
01088               chgts[i].src->swsData[chgts[i].bord].stPt =
01089             chgts[i].ptNo;
01090             }
01091           else
01092             {
01093               chgts[i].src->swsData[chgts[i].bord].enPt =
01094             chgts[i].ptNo;
01095             }
01096         }
01097           else if (chgts[i].type == 1)
01098         {
01099           if (chgts[i].src->getEdge(chgts[i].bord).st >
01100               chgts[i].src->getEdge(chgts[i].bord).en)
01101             {
01102               chgts[i].src->swsData[chgts[i].bord].stPt =
01103             chgts[i].ptNo;
01104             }
01105           else
01106             {
01107               chgts[i].src->swsData[chgts[i].bord].enPt =
01108             chgts[i].ptNo;
01109             }
01110         }
01111         }
01112 
01113       CheckAdjacencies (lastI, lastChgtPt, shapeHead, edgeHead);
01114 
01115       CheckEdges (lastI, lastChgtPt, a, b, mod);
01116 
01117       for (int i = lastChgtPt; i < lastI; i++)
01118         {
01119           if (pData[i].askForWindingS)
01120         {
01121           Shape *windS = pData[i].askForWindingS;
01122           int windB = pData[i].askForWindingB;
01123           pData[i].nextLinkedPoint =
01124             windS->swsData[windB].firstLinkedPoint;
01125           windS->swsData[windB].firstLinkedPoint = i;
01126         }
01127         }
01128 
01129     if (lastI < lastPointNo)
01130         {
01131           _pts[lastI] = getPoint(lastPointNo);
01132           pData[lastI] = pData[lastPointNo];
01133         }
01134       lastPointNo = lastI;
01135       _pts.resize(lastI + 1);
01136 
01137       lastChgtPt = lastPointNo;
01138       lastChange = rPtX[1];
01139       chgts.clear();
01140       edgeHead = -1;
01141       shapeHead = NULL;
01142     }
01143 
01144 
01145       if (isIntersection)
01146     {
01147       // les 2 events de part et d'autre de l'intersection
01148       // (celui de l'intersection a deja ete depile)
01149       intersL->RemoveEvent (*sEvts, LEFT);
01150       intersR->RemoveEvent (*sEvts, RIGHT);
01151 
01152       AddChgt (lastPointNo, lastChgtPt, shapeHead, edgeHead, INTERSECTION,
01153            intersL->src, intersL->bord, intersR->src, intersR->bord);
01154 
01155       intersL->SwapWithRight (*sTree, *sEvts);
01156 
01157       TesteIntersection (intersL, LEFT, true);
01158       TesteIntersection (intersR, RIGHT, true);
01159     }
01160       else
01161     {
01162       int cb;
01163 
01164       int nbUp = 0, nbDn = 0;
01165       int upNo = -1, dnNo = -1;
01166       cb = ptSh->getPoint(nPt).incidentEdge[FIRST];
01167       while (cb >= 0 && cb < ptSh->numberOfEdges())
01168         {
01169           if ((ptSh->getEdge(cb).st < ptSh->getEdge(cb).en
01170            && nPt == ptSh->getEdge(cb).en)
01171           || (ptSh->getEdge(cb).st > ptSh->getEdge(cb).en
01172               && nPt == ptSh->getEdge(cb).st))
01173         {
01174           upNo = cb;
01175           nbUp++;
01176         }
01177           if ((ptSh->getEdge(cb).st > ptSh->getEdge(cb).en
01178            && nPt == ptSh->getEdge(cb).en)
01179           || (ptSh->getEdge(cb).st < ptSh->getEdge(cb).en
01180               && nPt == ptSh->getEdge(cb).st))
01181         {
01182           dnNo = cb;
01183           nbDn++;
01184         }
01185           cb = ptSh->NextAt (nPt, cb);
01186         }
01187 
01188       if (nbDn <= 0)
01189         {
01190           upNo = -1;
01191         }
01192       if (upNo >= 0 && (SweepTree *) ptSh->swsData[upNo].misc == NULL)
01193         {
01194           upNo = -1;
01195         }
01196 
01197 //                      upNo=-1;
01198 
01199       bool doWinding = true;
01200 
01201       if (nbUp > 0)
01202         {
01203           cb = ptSh->getPoint(nPt).incidentEdge[FIRST];
01204           while (cb >= 0 && cb < ptSh->numberOfEdges())
01205         {
01206           if ((ptSh->getEdge(cb).st < ptSh->getEdge(cb).en
01207                && nPt == ptSh->getEdge(cb).en)
01208               || (ptSh->getEdge(cb).st > ptSh->getEdge(cb).en
01209               && nPt == ptSh->getEdge(cb).st))
01210             {
01211               if (cb != upNo)
01212             {
01213               SweepTree *node =
01214                 (SweepTree *) ptSh->swsData[cb].misc;
01215               if (node == NULL)
01216                 {
01217                 }
01218               else
01219                 {
01220                   AddChgt (lastPointNo, lastChgtPt, shapeHead,
01221                        edgeHead, EDGE_REMOVED, node->src, node->bord,
01222                        NULL, -1);
01223                   ptSh->swsData[cb].misc = NULL;
01224 
01225                   int onLeftB = -1, onRightB = -1;
01226                   Shape *onLeftS = NULL;
01227                   Shape *onRightS = NULL;
01228                   if (node->elem[LEFT])
01229                 {
01230                   onLeftB =
01231                     (static_cast <
01232                      SweepTree * >(node->elem[LEFT]))->bord;
01233                   onLeftS =
01234                     (static_cast <
01235                      SweepTree * >(node->elem[LEFT]))->src;
01236                 }
01237                   if (node->elem[RIGHT])
01238                 {
01239                   onRightB =
01240                     (static_cast <
01241                      SweepTree * >(node->elem[RIGHT]))->bord;
01242                   onRightS =
01243                     (static_cast <
01244                      SweepTree * >(node->elem[RIGHT]))->src;
01245                 }
01246 
01247                   node->Remove (*sTree, *sEvts, true);
01248                   if (onLeftS && onRightS)
01249                 {
01250                   SweepTree *onLeft =
01251                     (SweepTree *) onLeftS->swsData[onLeftB].
01252                     misc;
01253 //                                                                      SweepTree* onRight=(SweepTree*)onRightS->swsData[onRightB].misc;
01254                   if (onLeftS == ptSh
01255                       && (onLeftS->getEdge(onLeftB).en == nPt
01256                       || onLeftS->getEdge(onLeftB).st ==
01257                       nPt))
01258                     {
01259                     }
01260                   else
01261                     {
01262                       if (onRightS == ptSh
01263                       && (onRightS->getEdge(onRightB).en ==
01264                           nPt
01265                           || onRightS->getEdge(onRightB).
01266                           st == nPt))
01267                     {
01268                     }
01269                       else
01270                     {
01271                       TesteIntersection (onLeft, RIGHT, true);
01272                     }
01273                     }
01274                 }
01275                 }
01276             }
01277             }
01278           cb = ptSh->NextAt (nPt, cb);
01279         }
01280         }
01281 
01282       // traitement du "upNo devient dnNo"
01283       SweepTree *insertionNode = NULL;
01284       if (dnNo >= 0)
01285         {
01286           if (upNo >= 0)
01287         {
01288           SweepTree *node = (SweepTree *) ptSh->swsData[upNo].misc;
01289 
01290           AddChgt (lastPointNo, lastChgtPt, shapeHead, edgeHead, EDGE_REMOVED,
01291                node->src, node->bord, NULL, -1);
01292 
01293           ptSh->swsData[upNo].misc = NULL;
01294 
01295           node->RemoveEvents (*sEvts);
01296           node->ConvertTo (ptSh, dnNo, 1, lastPointNo);
01297           ptSh->swsData[dnNo].misc = node;
01298           TesteIntersection (node, RIGHT, true);
01299           TesteIntersection (node, LEFT, true);
01300           insertionNode = node;
01301 
01302           ptSh->swsData[dnNo].curPoint = lastPointNo;
01303 
01304           AddChgt (lastPointNo, lastChgtPt, shapeHead, edgeHead, EDGE_INSERTED,
01305                node->src, node->bord, NULL, -1);
01306         }
01307           else
01308         {
01309           SweepTree *node = sTree->add(ptSh, dnNo, 1, lastPointNo, this);
01310           ptSh->swsData[dnNo].misc = node;
01311           node->Insert (*sTree, *sEvts, this, lastPointNo, true);
01312 
01313           if (doWinding)
01314             {
01315               SweepTree *myLeft =
01316             static_cast < SweepTree * >(node->elem[LEFT]);
01317               if (myLeft)
01318             {
01319               pData[lastPointNo].askForWindingS = myLeft->src;
01320               pData[lastPointNo].askForWindingB = myLeft->bord;
01321             }
01322               else
01323             {
01324               pData[lastPointNo].askForWindingB = -1;
01325             }
01326               doWinding = false;
01327             }
01328 
01329           TesteIntersection (node, RIGHT, true);
01330           TesteIntersection (node, LEFT, true);
01331           insertionNode = node;
01332 
01333           ptSh->swsData[dnNo].curPoint = lastPointNo;
01334 
01335           AddChgt (lastPointNo, lastChgtPt, shapeHead, edgeHead, EDGE_INSERTED,
01336                node->src, node->bord, NULL, -1);
01337         }
01338         }
01339 
01340       if (nbDn > 1)
01341         {           // si nbDn == 1 , alors dnNo a deja ete traite
01342           cb = ptSh->getPoint(nPt).incidentEdge[FIRST];
01343           while (cb >= 0 && cb < ptSh->numberOfEdges())
01344         {
01345           if ((ptSh->getEdge(cb).st > ptSh->getEdge(cb).en
01346                && nPt == ptSh->getEdge(cb).en)
01347               || (ptSh->getEdge(cb).st < ptSh->getEdge(cb).en
01348               && nPt == ptSh->getEdge(cb).st))
01349             {
01350               if (cb != dnNo)
01351             {
01352               SweepTree *node = sTree->add(ptSh, cb, 1, lastPointNo, this);
01353               ptSh->swsData[cb].misc = node;
01354 //                                                      node->Insert(sTree,*sEvts,this,lastPointNo,true);
01355               node->InsertAt (*sTree, *sEvts, this, insertionNode,
01356                       nPt, true);
01357 
01358               if (doWinding)
01359                 {
01360                   SweepTree *myLeft =
01361                 static_cast < SweepTree * >(node->elem[LEFT]);
01362                   if (myLeft)
01363                 {
01364                   pData[lastPointNo].askForWindingS =
01365                     myLeft->src;
01366                   pData[lastPointNo].askForWindingB =
01367                     myLeft->bord;
01368                 }
01369                   else
01370                 {
01371                   pData[lastPointNo].askForWindingB = -1;
01372                 }
01373                   doWinding = false;
01374                 }
01375 
01376               TesteIntersection (node, RIGHT, true);
01377               TesteIntersection (node, LEFT, true);
01378 
01379               ptSh->swsData[cb].curPoint = lastPointNo;
01380 
01381               AddChgt (lastPointNo, lastChgtPt, shapeHead,
01382                    edgeHead, EDGE_INSERTED, node->src, node->bord, NULL,
01383                    -1);
01384             }
01385             }
01386           cb = ptSh->NextAt (nPt, cb);
01387         }
01388         }
01389     }
01390     }
01391   {
01392     int lastI = AssemblePoints (lastChgtPt, numberOfPoints());
01393 
01394 
01395     Shape *curSh = shapeHead;
01396     int curBo = edgeHead;
01397     while (curSh)
01398       {
01399     curSh->swsData[curBo].leftRnd =
01400       pData[curSh->swsData[curBo].leftRnd].newInd;
01401     curSh->swsData[curBo].rightRnd =
01402       pData[curSh->swsData[curBo].rightRnd].newInd;
01403 
01404     Shape *neSh = curSh->swsData[curBo].nextSh;
01405     curBo = curSh->swsData[curBo].nextBo;
01406     curSh = neSh;
01407       }
01408 
01409     /* FIXME: this kind of code seems to appear frequently */
01410     for (unsigned int i = 0; i < chgts.size(); i++)
01411       {
01412     chgts[i].ptNo = pData[chgts[i].ptNo].newInd;
01413     if (chgts[i].type == 0)
01414       {
01415         if (chgts[i].src->getEdge(chgts[i].bord).st <
01416         chgts[i].src->getEdge(chgts[i].bord).en)
01417           {
01418         chgts[i].src->swsData[chgts[i].bord].stPt = chgts[i].ptNo;
01419           }
01420         else
01421           {
01422         chgts[i].src->swsData[chgts[i].bord].enPt = chgts[i].ptNo;
01423           }
01424       }
01425     else if (chgts[i].type == 1)
01426       {
01427         if (chgts[i].src->getEdge(chgts[i].bord).st >
01428         chgts[i].src->getEdge(chgts[i].bord).en)
01429           {
01430         chgts[i].src->swsData[chgts[i].bord].stPt = chgts[i].ptNo;
01431           }
01432         else
01433           {
01434         chgts[i].src->swsData[chgts[i].bord].enPt = chgts[i].ptNo;
01435           }
01436       }
01437       }
01438 
01439     CheckAdjacencies (lastI, lastChgtPt, shapeHead, edgeHead);
01440 
01441     CheckEdges (lastI, lastChgtPt, a, b, mod);
01442 
01443     for (int i = lastChgtPt; i < lastI; i++)
01444       {
01445     if (pData[i].askForWindingS)
01446       {
01447         Shape *windS = pData[i].askForWindingS;
01448         int windB = pData[i].askForWindingB;
01449         pData[i].nextLinkedPoint = windS->swsData[windB].firstLinkedPoint;
01450         windS->swsData[windB].firstLinkedPoint = i;
01451       }
01452       }
01453 
01454     _pts.resize(lastI);
01455 
01456     edgeHead = -1;
01457     shapeHead = NULL;
01458   }
01459 
01460   chgts.clear();
01461   clearIncidenceData();
01462 
01463 //      Plot(190,70,6,400,400,true,false,true,true);
01464 
01465   if ( mod == bool_op_cut ) {
01466     AssembleAretes (fill_justDont);
01467     // dupliquer les aretes de la coupure
01468     int i=numberOfEdges()-1;
01469     for (;i>=0;i--) {
01470       if ( ebData[i].pathID == cutPathID ) {
01471         // on duplique
01472         int nEd=AddEdge(getEdge(i).en,getEdge(i).st);
01473         ebData[nEd].pathID=cutPathID;
01474         ebData[nEd].pieceID=ebData[i].pieceID;
01475         ebData[nEd].tSt=ebData[i].tEn;
01476         ebData[nEd].tEn=ebData[i].tSt;
01477         eData[nEd].weight=eData[i].weight;
01478         // lui donner les firstlinkedpoitn si besoin
01479         if ( getEdge(i).en >= getEdge(i).st ) {
01480           int cp = swsData[i].firstLinkedPoint;
01481           while (cp >= 0) {
01482             pData[cp].askForWindingB = nEd;
01483             cp = pData[cp].nextLinkedPoint;
01484           }
01485           swsData[nEd].firstLinkedPoint = swsData[i].firstLinkedPoint;
01486           swsData[i].firstLinkedPoint=-1;
01487         }
01488       }
01489     }
01490   } else if ( mod == bool_op_slice ) {
01491   } else {
01492     AssembleAretes ();
01493   }
01494   
01495   for (int i = 0; i < numberOfPoints(); i++)
01496     {
01497       _pts[i].oldDegree = getPoint(i).totalDegree();
01498     }
01499 
01500   _need_edges_sorting = true;
01501   if ( mod == bool_op_slice ) {
01502   } else {
01503     GetWindings (a, b, mod, false);
01504   }
01505 //      Plot(190,70,6,400,400,true,true,true,true);
01506 
01507   if (mod == bool_op_symdiff)
01508   {
01509     for (int i = 0; i < numberOfEdges(); i++)
01510     {
01511       swdData[i].leW = swdData[i].leW % 2;
01512       if (swdData[i].leW < 0)
01513         swdData[i].leW = -swdData[i].leW;
01514       swdData[i].riW = swdData[i].riW;
01515       if (swdData[i].riW < 0)
01516         swdData[i].riW = -swdData[i].riW;
01517       
01518       if (swdData[i].leW > 0 && swdData[i].riW <= 0)
01519         {
01520           eData[i].weight = 1;
01521         }
01522       else if (swdData[i].leW <= 0 && swdData[i].riW > 0)
01523         {
01524           Inverse (i);
01525           eData[i].weight = 1;
01526         }
01527       else
01528         {
01529           eData[i].weight = 0;
01530           SubEdge (i);
01531           i--;
01532         }
01533     }
01534   }
01535   else if (mod == bool_op_union || mod == bool_op_diff)
01536   {
01537     for (int i = 0; i < numberOfEdges(); i++)
01538     {
01539       if (swdData[i].leW > 0 && swdData[i].riW <= 0)
01540         {
01541           eData[i].weight = 1;
01542         }
01543       else if (swdData[i].leW <= 0 && swdData[i].riW > 0)
01544         {
01545           Inverse (i);
01546           eData[i].weight = 1;
01547         }
01548       else
01549         {
01550           eData[i].weight = 0;
01551           SubEdge (i);
01552           i--;
01553         }
01554     }
01555   }
01556   else if (mod == bool_op_inters)
01557   {
01558     for (int i = 0; i < numberOfEdges(); i++)
01559     {
01560       if (swdData[i].leW > 1 && swdData[i].riW <= 1)
01561         {
01562           eData[i].weight = 1;
01563         }
01564       else if (swdData[i].leW <= 1 && swdData[i].riW > 1)
01565         {
01566           Inverse (i);
01567           eData[i].weight = 1;
01568         }
01569       else
01570         {
01571           eData[i].weight = 0;
01572           SubEdge (i);
01573           i--;
01574         }
01575     }
01576   } else if ( mod == bool_op_cut ) {
01577     // inverser les aretes de la coupe au besoin
01578     for (int i=0;i<numberOfEdges();i++) {
01579       if ( getEdge(i).st < 0 || getEdge(i).en < 0 ) {
01580         if ( i < numberOfEdges()-1 ) {
01581           // decaler les askForWinding
01582           int cp = swsData[numberOfEdges()-1].firstLinkedPoint;
01583           while (cp >= 0) {
01584             pData[cp].askForWindingB = i;
01585             cp = pData[cp].nextLinkedPoint;
01586           }
01587         }
01588         SwapEdges(i,numberOfEdges()-1);
01589         SubEdge(numberOfEdges()-1);
01590 //        SubEdge(i);
01591         i--;
01592       } else if ( ebData[i].pathID == cutPathID ) {
01593         swdData[i].leW=swdData[i].leW%2;
01594         swdData[i].riW=swdData[i].riW%2;
01595         if ( swdData[i].leW < swdData[i].riW ) {
01596           Inverse(i);
01597         }
01598       }
01599     }
01600   } else if ( mod == bool_op_slice ) {
01601     // supprimer les aretes de la coupe
01602     int i=numberOfEdges()-1;
01603     for (;i>=0;i--) {
01604       if ( ebData[i].pathID == cutPathID || getEdge(i).st < 0 || getEdge(i).en < 0 ) {
01605         SubEdge(i);
01606       }
01607     }
01608   }
01609   else
01610   {
01611     for (int i = 0; i < numberOfEdges(); i++)
01612     {
01613       if (swdData[i].leW > 0 && swdData[i].riW <= 0)
01614         {
01615           eData[i].weight = 1;
01616         }
01617       else if (swdData[i].leW <= 0 && swdData[i].riW > 0)
01618         {
01619           Inverse (i);
01620           eData[i].weight = 1;
01621         }
01622       else
01623         {
01624           eData[i].weight = 0;
01625           SubEdge (i);
01626           i--;
01627         }
01628     }
01629   }
01630   
01631   delete sTree;
01632   sTree = NULL;
01633   delete sEvts;
01634   sEvts = NULL;
01635   
01636   if ( mod == bool_op_cut ) {
01637     // on garde le askForWinding
01638   } else {
01639     MakePointData (false);
01640   }
01641   MakeEdgeData (false);
01642   MakeSweepSrcData (false);
01643   MakeSweepDestData (false);
01644   a->CleanupSweep ();
01645   b->CleanupSweep ();
01646 
01647   if (directedEulerian(this) == false)
01648     {
01649 //              printf( "pas euclidian2");
01650       _pts.clear();
01651       _aretes.clear();
01652       return shape_euler_err;
01653     }
01654   type = shape_polygon;
01655   return 0;
01656 }
01657 
01658 // frontend to the TesteIntersection() below
01659 void Shape::TesteIntersection(SweepTree *t, Side s, bool onlyDiff)
01660 {
01661     SweepTree *tt = static_cast<SweepTree*>(t->elem[s]);
01662     if (tt == NULL) {
01663     return;
01664     }
01665 
01666     SweepTree *a = (s == LEFT) ? tt : t;
01667     SweepTree *b = (s == LEFT) ? t : tt;
01668 
01669     Geom::Point atx;
01670     double atl;
01671     double atr;
01672     if (TesteIntersection(a, b, atx, atl, atr, onlyDiff)) {
01673     sEvts->add(a, b, atx, atl, atr);
01674     }
01675 }
01676 
01677 // a crucial piece of code: computing intersections between segments
01678 bool
01679 Shape::TesteIntersection (SweepTree * iL, SweepTree * iR, Geom::Point &atx, double &atL, double &atR, bool onlyDiff)
01680 {
01681   int lSt = iL->src->getEdge(iL->bord).st, lEn = iL->src->getEdge(iL->bord).en;
01682   int rSt = iR->src->getEdge(iR->bord).st, rEn = iR->src->getEdge(iR->bord).en;
01683   Geom::Point ldir, rdir;
01684   ldir = iL->src->eData[iL->bord].rdx;
01685   rdir = iR->src->eData[iR->bord].rdx;
01686   // first, a round of checks to quickly dismiss edge which obviously dont intersect,
01687   // such as having disjoint bounding boxes
01688   if (lSt < lEn)
01689     {
01690     }
01691   else
01692     {
01693       int swap = lSt;
01694       lSt = lEn;
01695       lEn = swap;
01696       ldir = -ldir;
01697     }
01698   if (rSt < rEn)
01699     {
01700     }
01701   else
01702     {
01703       int swap = rSt;
01704       rSt = rEn;
01705       rEn = swap;
01706       rdir = -rdir;
01707     }
01708 
01709   if (iL->src->pData[lSt].rx[0] < iL->src->pData[lEn].rx[0])
01710     {
01711       if (iR->src->pData[rSt].rx[0] < iR->src->pData[rEn].rx[0])
01712     {
01713       if (iL->src->pData[lSt].rx[0] > iR->src->pData[rEn].rx[0])
01714         return false;
01715       if (iL->src->pData[lEn].rx[0] < iR->src->pData[rSt].rx[0])
01716         return false;
01717     }
01718       else
01719     {
01720       if (iL->src->pData[lSt].rx[0] > iR->src->pData[rSt].rx[0])
01721         return false;
01722       if (iL->src->pData[lEn].rx[0] < iR->src->pData[rEn].rx[0])
01723         return false;
01724     }
01725     }
01726   else
01727     {
01728       if (iR->src->pData[rSt].rx[0] < iR->src->pData[rEn].rx[0])
01729     {
01730       if (iL->src->pData[lEn].rx[0] > iR->src->pData[rEn].rx[0])
01731         return false;
01732       if (iL->src->pData[lSt].rx[0] < iR->src->pData[rSt].rx[0])
01733         return false;
01734     }
01735       else
01736     {
01737       if (iL->src->pData[lEn].rx[0] > iR->src->pData[rSt].rx[0])
01738         return false;
01739       if (iL->src->pData[lSt].rx[0] < iR->src->pData[rEn].rx[0])
01740         return false;
01741     }
01742     }
01743 
01744   double ang = cross (rdir, ldir);
01745 //      ang*=iL->src->eData[iL->bord].isqlength;
01746 //      ang*=iR->src->eData[iR->bord].isqlength;
01747   if (ang <= 0) return false;       // edges in opposite directions:  <-left  ... right ->
01748                                 // they can't intersect
01749 
01750   // d'abord tester les bords qui partent d'un meme point
01751   if (iL->src == iR->src && lSt == rSt)
01752     {
01753       if (iL->src == iR->src && lEn == rEn)
01754     return false;       // c'est juste un doublon
01755       atx = iL->src->pData[lSt].rx;
01756       atR = atL = -1;
01757       return true;      // l'ordre est mauvais
01758     }
01759   if (iL->src == iR->src && lEn == rEn)
01760     return false;       // rien a faire=ils vont terminer au meme endroit
01761 
01762   // tester si on est dans une intersection multiple
01763 
01764   if (onlyDiff && iL->src == iR->src)
01765     return false;
01766 
01767   // on reprend les vrais points
01768   lSt = iL->src->getEdge(iL->bord).st;
01769   lEn = iL->src->getEdge(iL->bord).en;
01770   rSt = iR->src->getEdge(iR->bord).st;
01771   rEn = iR->src->getEdge(iR->bord).en;
01772 
01773   // compute intersection (if there is one)
01774   // Boissonat anr Preparata said in one paper that double precision floats were sufficient for get single precision
01775   // coordinates for the intersection, if the endpoints are single precision. i hope they're right...
01776   {
01777     Geom::Point sDiff, eDiff;
01778     double slDot, elDot;
01779     double srDot, erDot;
01780     sDiff = iL->src->pData[lSt].rx - iR->src->pData[rSt].rx;
01781     eDiff = iL->src->pData[lEn].rx - iR->src->pData[rSt].rx;
01782     srDot = cross (sDiff,rdir);
01783     erDot = cross (eDiff,rdir);
01784     sDiff = iR->src->pData[rSt].rx - iL->src->pData[lSt].rx;
01785     eDiff = iR->src->pData[rEn].rx - iL->src->pData[lSt].rx;
01786     slDot = cross (sDiff,ldir);
01787     elDot = cross (eDiff,ldir);
01788 
01789     if ((srDot >= 0 && erDot >= 0) || (srDot <= 0 && erDot <= 0))
01790       {
01791     if (srDot == 0)
01792       {
01793         if (lSt < lEn)
01794           {
01795         atx = iL->src->pData[lSt].rx;
01796         atL = 0;
01797         atR = slDot / (slDot - elDot);
01798         return true;
01799           }
01800         else
01801           {
01802         return false;
01803           }
01804       }
01805     else if (erDot == 0)
01806       {
01807         if (lSt > lEn)
01808           {
01809         atx = iL->src->pData[lEn].rx;
01810         atL = 1;
01811         atR = slDot / (slDot - elDot);
01812         return true;
01813           }
01814         else
01815           {
01816         return false;
01817           }
01818       }
01819     if (srDot > 0 && erDot > 0)
01820       {
01821         if (rEn < rSt)
01822           {
01823         if (srDot < erDot)
01824           {
01825             if (lSt < lEn)
01826               {
01827             atx = iL->src->pData[lSt].rx;
01828             atL = 0;
01829             atR = slDot / (slDot - elDot);
01830             return true;
01831               }
01832           }
01833         else
01834           {
01835             if (lEn < lSt)
01836               {
01837             atx = iL->src->pData[lEn].rx;
01838             atL = 1;
01839             atR = slDot / (slDot - elDot);
01840             return true;
01841               }
01842           }
01843           }
01844       }
01845     if (srDot < 0 && erDot < 0)
01846       {
01847         if (rEn > rSt)
01848           {
01849         if (srDot > erDot)
01850           {
01851             if (lSt < lEn)
01852               {
01853             atx = iL->src->pData[lSt].rx;
01854             atL = 0;
01855             atR = slDot / (slDot - elDot);
01856             return true;
01857               }
01858           }
01859         else
01860           {
01861             if (lEn < lSt)
01862               {
01863             atx = iL->src->pData[lEn].rx;
01864             atL = 1;
01865             atR = slDot / (slDot - elDot);
01866             return true;
01867               }
01868           }
01869           }
01870       }
01871     return false;
01872       }
01873     if ((slDot >= 0 && elDot >= 0) || (slDot <= 0 && elDot <= 0))
01874       {
01875     if (slDot == 0)
01876       {
01877         if (rSt < rEn)
01878           {
01879         atx = iR->src->pData[rSt].rx;
01880         atR = 0;
01881         atL = srDot / (srDot - erDot);
01882         return true;
01883           }
01884         else
01885           {
01886         return false;
01887           }
01888       }
01889     else if (elDot == 0)
01890       {
01891         if (rSt > rEn)
01892           {
01893         atx = iR->src->pData[rEn].rx;
01894         atR = 1;
01895         atL = srDot / (srDot - erDot);
01896         return true;
01897           }
01898         else
01899           {
01900         return false;
01901           }
01902       }
01903     if (slDot > 0 && elDot > 0)
01904       {
01905         if (lEn > lSt)
01906           {
01907         if (slDot < elDot)
01908           {
01909             if (rSt < rEn)
01910               {
01911             atx = iR->src->pData[rSt].rx;
01912             atR = 0;
01913             atL = srDot / (srDot - erDot);
01914             return true;
01915               }
01916           }
01917         else
01918           {
01919             if (rEn < rSt)
01920               {
01921             atx = iR->src->pData[rEn].rx;
01922             atR = 1;
01923             atL = srDot / (srDot - erDot);
01924             return true;
01925               }
01926           }
01927           }
01928       }
01929     if (slDot < 0 && elDot < 0)
01930       {
01931         if (lEn < lSt)
01932           {
01933         if (slDot > elDot)
01934           {
01935             if (rSt < rEn)
01936               {
01937             atx = iR->src->pData[rSt].rx;
01938             atR = 0;
01939             atL = srDot / (srDot - erDot);
01940             return true;
01941               }
01942           }
01943         else
01944           {
01945             if (rEn < rSt)
01946               {
01947             atx = iR->src->pData[rEn].rx;
01948             atR = 1;
01949             atL = srDot / (srDot - erDot);
01950             return true;
01951               }
01952           }
01953           }
01954       }
01955     return false;
01956       }
01957 
01958 /*      double  slb=slDot-elDot,srb=srDot-erDot;
01959         if ( slb < 0 ) slb=-slb;
01960         if ( srb < 0 ) srb=-srb;*/
01961     if (iL->src->eData[iL->bord].siEd > iR->src->eData[iR->bord].siEd)
01962       {
01963     atx =
01964       (slDot * iR->src->pData[rEn].rx -
01965        elDot * iR->src->pData[rSt].rx) / (slDot - elDot);
01966       }
01967     else
01968       {
01969     atx =
01970       (srDot * iL->src->pData[lEn].rx -
01971        erDot * iL->src->pData[lSt].rx) / (srDot - erDot);
01972       }
01973     atL = srDot / (srDot - erDot);
01974     atR = slDot / (slDot - elDot);
01975     return true;
01976   }
01977 
01978   return true;
01979 }
01980 
01981 int
01982 Shape::PushIncidence (Shape * a, int cb, int pt, double theta)
01983 {
01984   if (theta < 0 || theta > 1)
01985     return -1;
01986 
01987   if (nbInc >= maxInc)
01988     {
01989       maxInc = 2 * nbInc + 1;
01990       iData =
01991     (incidenceData *) g_realloc(iData, maxInc * sizeof (incidenceData));
01992     }
01993   int n = nbInc++;
01994   iData[n].nextInc = a->swsData[cb].firstLinkedPoint;
01995   iData[n].pt = pt;
01996   iData[n].theta = theta;
01997   a->swsData[cb].firstLinkedPoint = n;
01998   return n;
01999 }
02000 
02001 int
02002 Shape::CreateIncidence (Shape * a, int no, int nPt)
02003 {
02004   Geom::Point adir, diff;
02005   adir = a->eData[no].rdx;
02006   diff = getPoint(nPt).x - a->pData[a->getEdge(no).st].rx;
02007   double t = dot (diff, adir);
02008   t *= a->eData[no].ilength;
02009   return PushIncidence (a, no, nPt, t);
02010 }
02011 
02012 int
02013 Shape::Winding (int nPt) const 
02014 {
02015   int askTo = pData[nPt].askForWindingB;
02016   if (askTo < 0 || askTo >= numberOfEdges())
02017     return 0;
02018   if (getEdge(askTo).st < getEdge(askTo).en)
02019     {
02020       return swdData[askTo].leW;
02021     }
02022   else
02023     {
02024       return swdData[askTo].riW;
02025     }
02026   return 0;
02027 }
02028 
02029 int
02030 Shape::Winding (const Geom::Point px) const 
02031 {
02032   int lr = 0, ll = 0, rr = 0;
02033 
02034   for (int i = 0; i < numberOfEdges(); i++)
02035     {
02036       Geom::Point adir, diff, ast, aen;
02037       adir = eData[i].rdx;
02038 
02039       ast = pData[getEdge(i).st].rx;
02040       aen = pData[getEdge(i).en].rx;
02041 
02042       int nWeight = eData[i].weight;
02043 
02044       if (ast[0] < aen[0])
02045     {
02046       if (ast[0] > px[0])
02047         continue;
02048       if (aen[0] < px[0])
02049         continue;
02050     }
02051       else
02052     {
02053       if (ast[0] < px[0])
02054         continue;
02055       if (aen[0] > px[0])
02056         continue;
02057     }
02058       if (ast[0] == px[0])
02059     {
02060       if (ast[1] >= px[1])
02061         continue;
02062       if (aen[0] == px[0])
02063         continue;
02064       if (aen[0] < px[0])
02065         ll += nWeight;
02066       else
02067         rr -= nWeight;
02068       continue;
02069     }
02070       if (aen[0] == px[0])
02071     {
02072       if (aen[1] >= px[1])
02073         continue;
02074       if (ast[0] == px[0])
02075         continue;
02076       if (ast[0] < px[0])
02077         ll -= nWeight;
02078       else
02079         rr += nWeight;
02080       continue;
02081     }
02082 
02083       if (ast[1] < aen[1])
02084     {
02085       if (ast[1] >= px[1])
02086         continue;
02087     }
02088       else
02089     {
02090       if (aen[1] >= px[1])
02091         continue;
02092     }
02093 
02094       diff = px - ast;
02095       double cote = cross (diff,adir);
02096       if (cote == 0)
02097     continue;
02098       if (cote < 0)
02099     {
02100       if (ast[0] > px[0])
02101         lr += nWeight;
02102     }
02103       else
02104     {
02105       if (ast[0] < px[0])
02106         lr -= nWeight;
02107     }
02108     }
02109   return lr + (ll + rr) / 2;
02110 }
02111 
02112 // merging duplicate points and edges
02113 int
02114 Shape::AssemblePoints (int st, int en)
02115 {
02116   if (en > st) {
02117    for (int i = st; i < en; i++) pData[i].oldInd = i;
02118 //              SortPoints(st,en-1);
02119     SortPointsByOldInd (st, en - 1); // SortPointsByOldInd() is required here, because of the edges we have
02120                                        // associated with the point for later computation of winding numbers.
02121                                        // specifically, we need the first point we treated, it's the only one with a valid
02122                                        // associated edge (man, that was a nice bug).
02123      for (int i = st; i < en; i++) pData[pData[i].oldInd].newInd = i;
02124 
02125      int lastI = st;
02126      for (int i = st; i < en; i++) {
02127           pData[i].pending = lastI++;
02128           if (i > st && getPoint(i - 1).x[0] == getPoint(i).x[0] && getPoint(i - 1).x[1] == getPoint(i).x[1]) {
02129             pData[i].pending = pData[i - 1].pending;
02130             if (pData[pData[i].pending].askForWindingS == NULL) {
02131                 pData[pData[i].pending].askForWindingS = pData[i].askForWindingS;
02132                 pData[pData[i].pending].askForWindingB = pData[i].askForWindingB;
02133               } else {
02134                 if (pData[pData[i].pending].askForWindingS == pData[i].askForWindingS
02135               && pData[pData[i].pending].askForWindingB == pData[i].askForWindingB) {
02136               // meme bord, c bon
02137                 } else {
02138               // meme point, mais pas le meme bord: ouille!
02139               // il faut prendre le bord le plus a gauche
02140               // en pratique, n'arrive que si 2 maxima sont dans la meme case -> le mauvais choix prend une arete incidente 
02141               // au bon choix
02142 //                                              printf("doh");
02143                 }
02144               }
02145             lastI--;
02146           } else {
02147             if (i > pData[i].pending) {
02148                 _pts[pData[i].pending].x = getPoint(i).x;
02149                 pData[pData[i].pending].rx = getPoint(i).x;
02150                 pData[pData[i].pending].askForWindingS = pData[i].askForWindingS;
02151                 pData[pData[i].pending].askForWindingB = pData[i].askForWindingB;
02152               }
02153           }
02154         }
02155       for (int i = st; i < en; i++) pData[i].newInd = pData[pData[i].newInd].pending;
02156       return lastI;
02157   }
02158   return en;
02159 }
02160 
02161 void
02162 Shape::AssemblePoints (Shape * a)
02163 {
02164   if (hasPoints())
02165     {
02166       int lastI = AssemblePoints (0, numberOfPoints());
02167 
02168       for (int i = 0; i < a->numberOfEdges(); i++)
02169     {
02170       a->swsData[i].stPt = pData[a->swsData[i].stPt].newInd;
02171       a->swsData[i].enPt = pData[a->swsData[i].enPt].newInd;
02172     }
02173       for (int i = 0; i < nbInc; i++)
02174     iData[i].pt = pData[iData[i].pt].newInd;
02175 
02176       _pts.resize(lastI);
02177     }
02178 }
02179 void
02180 Shape::AssembleAretes (FillRule directed)
02181 {
02182   if ( directed == fill_justDont && _has_back_data == false ) {
02183     directed=fill_nonZero;
02184   }
02185   
02186   for (int i = 0; i < numberOfPoints(); i++) {
02187     if (getPoint(i).totalDegree() == 2) {
02188       int cb, cc;
02189       cb = getPoint(i).incidentEdge[FIRST];
02190       cc = getPoint(i).incidentEdge[LAST];
02191       bool  doublon=false;
02192       if ((getEdge(cb).st == getEdge(cc).st && getEdge(cb).en == getEdge(cc).en)
02193           || (getEdge(cb).st == getEdge(cc).en && getEdge(cb).en == getEdge(cc).en)) doublon=true;
02194       if ( directed == fill_justDont ) {
02195         if ( doublon ) {
02196           if ( ebData[cb].pathID > ebData[cc].pathID ) {
02197             cc = getPoint(i).incidentEdge[FIRST]; // on swappe pour enlever cc
02198             cb = getPoint(i).incidentEdge[LAST];
02199           } else if ( ebData[cb].pathID == ebData[cc].pathID ) {
02200             if ( ebData[cb].pieceID > ebData[cc].pieceID ) {
02201               cc = getPoint(i).incidentEdge[FIRST]; // on swappe pour enlever cc
02202               cb = getPoint(i).incidentEdge[LAST];
02203             } else if ( ebData[cb].pieceID == ebData[cc].pieceID ) { 
02204               if ( ebData[cb].tSt > ebData[cc].tSt ) {
02205                 cc = getPoint(i).incidentEdge[FIRST]; // on swappe pour enlever cc
02206                 cb = getPoint(i).incidentEdge[LAST];
02207               }
02208             }
02209           }
02210         }
02211         if ( doublon ) eData[cc].weight = 0;
02212       } else {
02213       }
02214       if ( doublon ) {
02215         if (getEdge(cb).st == getEdge(cc).st) {
02216           eData[cb].weight += eData[cc].weight;
02217         } else {
02218           eData[cb].weight -= eData[cc].weight;
02219         }
02220           eData[cc].weight = 0;
02221         
02222           if (swsData[cc].firstLinkedPoint >= 0) {
02223           int cp = swsData[cc].firstLinkedPoint;
02224           while (cp >= 0) {
02225             pData[cp].askForWindingB = cb;
02226             cp = pData[cp].nextLinkedPoint;
02227           }
02228           if (swsData[cb].firstLinkedPoint < 0) {
02229             swsData[cb].firstLinkedPoint = swsData[cc].firstLinkedPoint;
02230           } else {
02231             int ncp = swsData[cb].firstLinkedPoint;
02232             while (pData[ncp].nextLinkedPoint >= 0) {
02233               ncp = pData[ncp].nextLinkedPoint;
02234             }
02235             pData[ncp].nextLinkedPoint = swsData[cc].firstLinkedPoint;
02236           }
02237         }
02238         
02239           DisconnectStart (cc);
02240           DisconnectEnd (cc);
02241           if (numberOfEdges() > 1) {
02242           int cp = swsData[numberOfEdges() - 1].firstLinkedPoint;
02243           while (cp >= 0) {
02244             pData[cp].askForWindingB = cc;
02245             cp = pData[cp].nextLinkedPoint;
02246           }
02247         }
02248           SwapEdges (cc, numberOfEdges() - 1);
02249           if (cb == numberOfEdges() - 1) {
02250           cb = cc;
02251         }
02252           _aretes.pop_back();
02253         }
02254     } else {
02255       int cb;
02256       cb = getPoint(i).incidentEdge[FIRST];
02257       while (cb >= 0 && cb < numberOfEdges()) {
02258           int other = Other (i, cb);
02259           int cc;
02260           cc = getPoint(i).incidentEdge[FIRST];
02261           while (cc >= 0 && cc < numberOfEdges()) {
02262           int ncc = NextAt (i, cc);
02263           bool  doublon=false;
02264           if (cc != cb && Other (i, cc) == other ) doublon=true;
02265           if ( directed == fill_justDont ) {
02266             if ( doublon ) {
02267               if ( ebData[cb].pathID > ebData[cc].pathID ) {
02268                 doublon=false;
02269               } else if ( ebData[cb].pathID == ebData[cc].pathID ) {
02270                 if ( ebData[cb].pieceID > ebData[cc].pieceID ) {
02271                   doublon=false;
02272                 } else if ( ebData[cb].pieceID == ebData[cc].pieceID ) { 
02273                   if ( ebData[cb].tSt > ebData[cc].tSt ) {
02274                     doublon=false;
02275                   }
02276                 }
02277               }
02278             }
02279             if ( doublon ) eData[cc].weight = 0;
02280           } else {
02281           }
02282           if ( doublon ) {
02283 //            if (cc != cb && Other (i, cc) == other) {
02284             // doublon
02285             if (getEdge(cb).st == getEdge(cc).st) {
02286               eData[cb].weight += eData[cc].weight;
02287             } else {
02288               eData[cb].weight -= eData[cc].weight;
02289             }
02290             eData[cc].weight = 0;
02291             
02292             if (swsData[cc].firstLinkedPoint >= 0) {
02293               int cp = swsData[cc].firstLinkedPoint;
02294               while (cp >= 0) {
02295                 pData[cp].askForWindingB = cb;
02296                 cp = pData[cp].nextLinkedPoint;
02297               }
02298               if (swsData[cb].firstLinkedPoint < 0) {
02299                 swsData[cb].firstLinkedPoint = swsData[cc].firstLinkedPoint;
02300               } else {
02301                 int ncp = swsData[cb].firstLinkedPoint;
02302                 while (pData[ncp].nextLinkedPoint >= 0) {
02303                   ncp = pData[ncp].nextLinkedPoint;
02304                 }
02305                 pData[ncp].nextLinkedPoint = swsData[cc].firstLinkedPoint;
02306               }
02307             }
02308             
02309             DisconnectStart (cc);
02310             DisconnectEnd (cc);
02311             if (numberOfEdges() > 1) {
02312               int cp = swsData[numberOfEdges() - 1].firstLinkedPoint;
02313               while (cp >= 0) {
02314                 pData[cp].askForWindingB = cc;
02315                 cp = pData[cp].nextLinkedPoint;
02316               }
02317             }
02318             SwapEdges (cc, numberOfEdges() - 1);
02319             if (cb == numberOfEdges() - 1) {
02320               cb = cc;
02321             }
02322             if (ncc == numberOfEdges() - 1) {
02323               ncc = cc;
02324             }
02325         _aretes.pop_back();
02326           }
02327           cc = ncc;
02328         }
02329           cb = NextAt (i, cb);
02330         }
02331     }
02332   }
02333   
02334   if ( directed == fill_justDont ) {
02335     for (int i = 0; i < numberOfEdges(); i++)  {
02336       if (eData[i].weight == 0) {
02337 //        SubEdge(i);
02338  //       i--;
02339       } else {
02340         if (eData[i].weight < 0) Inverse (i);
02341       }
02342     }
02343   } else {
02344     for (int i = 0; i < numberOfEdges(); i++)  {
02345       if (eData[i].weight == 0) {
02346         //                      SubEdge(i);
02347         //                      i--;
02348       } else {
02349         if (eData[i].weight < 0) Inverse (i);
02350       }
02351     }
02352   }
02353 }
02354 void
02355 Shape::GetWindings (Shape * /*a*/, Shape * /*b*/, BooleanOp /*mod*/, bool brutal)
02356 {
02357   // preparation du parcours
02358   for (int i = 0; i < numberOfEdges(); i++)
02359     {
02360       swdData[i].misc = 0;
02361       swdData[i].precParc = swdData[i].suivParc = -1;
02362     }
02363 
02364   // chainage
02365   SortEdges ();
02366 
02367   int searchInd = 0;
02368 
02369   int lastPtUsed = 0;
02370   do
02371     {
02372       int startBord = -1;
02373       int outsideW = 0;
02374       {
02375     int fi = 0;
02376     for (fi = lastPtUsed; fi < numberOfPoints(); fi++)
02377       {
02378         if (getPoint(fi).incidentEdge[FIRST] >= 0 && swdData[getPoint(fi).incidentEdge[FIRST]].misc == 0)
02379           break;
02380       }
02381     lastPtUsed = fi + 1;
02382     if (fi < numberOfPoints())
02383       {
02384         int bestB = getPoint(fi).incidentEdge[FIRST];
02385         if (bestB >= 0)
02386           {
02387         startBord = bestB;
02388         if (fi == 0)
02389           {
02390             outsideW = 0;
02391           }
02392         else
02393           {
02394             if (brutal)
02395               {
02396             outsideW = Winding (getPoint(fi).x);
02397               }
02398             else
02399               {
02400             outsideW = Winding (fi);
02401               }
02402           }
02403     if ( getPoint(fi).totalDegree() == 1 ) {
02404       if ( fi == getEdge(startBord).en ) {
02405         if ( eData[startBord].weight == 0 ) {
02406           // on se contente d'inverser
02407           Inverse(startBord);
02408         } else {
02409           // on passe le askForWinding (sinon ca va rester startBord)
02410           pData[getEdge(startBord).st].askForWindingB=pData[getEdge(startBord).en].askForWindingB;
02411         }
02412       }
02413     }
02414         if (getEdge(startBord).en == fi)
02415           outsideW += eData[startBord].weight;
02416           }
02417       }
02418       }
02419       if (startBord >= 0)
02420     {
02421       // parcours en profondeur pour mettre les leF et riF a leurs valeurs
02422       swdData[startBord].misc = (void *) 1;
02423       swdData[startBord].leW = outsideW;
02424       swdData[startBord].riW = outsideW - eData[startBord].weight;
02425 //    if ( doDebug ) printf("part de %d\n",startBord);
02426       int curBord = startBord;
02427       bool curDir = true;
02428       swdData[curBord].precParc = -1;
02429       swdData[curBord].suivParc = -1;
02430       do
02431         {
02432           int cPt;
02433           if (curDir)
02434         cPt = getEdge(curBord).en;
02435           else
02436         cPt = getEdge(curBord).st;
02437           int nb = curBord;
02438 //        if ( doDebug ) printf("de curBord= %d avec leF= %d et riF= %d  -> ",curBord,swdData[curBord].leW,swdData[curBord].riW);
02439           do
02440         {
02441           int nnb = -1;
02442           if (getEdge(nb).en == cPt)
02443             {
02444               outsideW = swdData[nb].riW;
02445               nnb = CyclePrevAt (cPt, nb);
02446             }
02447           else
02448             {
02449               outsideW = swdData[nb].leW;
02450               nnb = CyclePrevAt (cPt, nb);
02451             }
02452           if (nnb == nb)
02453             {
02454               // cul-de-sac
02455               nb = -1;
02456               break;
02457             }
02458           nb = nnb;
02459         }
02460           while (nb >= 0 && nb != curBord && swdData[nb].misc != 0);
02461           if (nb < 0 || nb == curBord)
02462         {
02463           // retour en arriere
02464           int oPt;
02465           if (curDir)
02466             oPt = getEdge(curBord).st;
02467           else
02468             oPt = getEdge(curBord).en;
02469           curBord = swdData[curBord].precParc;
02470 //    if ( doDebug ) printf("retour vers %d\n",curBord);
02471           if (curBord < 0)
02472             break;
02473           if (oPt == getEdge(curBord).en)
02474             curDir = true;
02475           else
02476             curDir = false;
02477         }
02478           else
02479         {
02480           swdData[nb].misc = (void *) 1;
02481           swdData[nb].ind = searchInd++;
02482           if (cPt == getEdge(nb).st)
02483             {
02484               swdData[nb].riW = outsideW;
02485               swdData[nb].leW = outsideW + eData[nb].weight;
02486             }
02487           else
02488             {
02489               swdData[nb].leW = outsideW;
02490               swdData[nb].riW = outsideW - eData[nb].weight;
02491             }
02492           swdData[nb].precParc = curBord;
02493           swdData[curBord].suivParc = nb;
02494           curBord = nb;
02495 //        if ( doDebug ) printf("suite %d\n",curBord);
02496           if (cPt == getEdge(nb).en)
02497             curDir = false;
02498           else
02499             curDir = true;
02500         }
02501         }
02502       while (1 /*swdData[curBord].precParc >= 0 */ );
02503       // fin du cas non-oriente
02504     }
02505     }
02506   while (lastPtUsed < numberOfPoints());
02507 //      fflush(stdout);
02508 }
02509 
02510 bool
02511 Shape::TesteIntersection (Shape * ils, Shape * irs, int ilb, int irb,
02512                           Geom::Point &atx, double &atL, double &atR,
02513               bool /*onlyDiff*/)
02514 {
02515   int lSt = ils->getEdge(ilb).st, lEn = ils->getEdge(ilb).en;
02516   int rSt = irs->getEdge(irb).st, rEn = irs->getEdge(irb).en;
02517   if (lSt == rSt || lSt == rEn)
02518     {
02519       return false;
02520     }
02521   if (lEn == rSt || lEn == rEn)
02522     {
02523       return false;
02524     }
02525 
02526   Geom::Point ldir, rdir;
02527   ldir = ils->eData[ilb].rdx;
02528   rdir = irs->eData[irb].rdx;
02529 
02530   double il = ils->pData[lSt].rx[0], it = ils->pData[lSt].rx[1], ir =
02531     ils->pData[lEn].rx[0], ib = ils->pData[lEn].rx[1];
02532   if (il > ir)
02533     {
02534       double swf = il;
02535       il = ir;
02536       ir = swf;
02537     }
02538   if (it > ib)
02539     {
02540       double swf = it;
02541       it = ib;
02542       ib = swf;
02543     }
02544   double jl = irs->pData[rSt].rx[0], jt = irs->pData[rSt].rx[1], jr =
02545     irs->pData[rEn].rx[0], jb = irs->pData[rEn].rx[1];
02546   if (jl > jr)
02547     {
02548       double swf = jl;
02549       jl = jr;
02550       jr = swf;
02551     }
02552   if (jt > jb)
02553     {
02554       double swf = jt;
02555       jt = jb;
02556       jb = swf;
02557     }
02558 
02559   if (il > jr || it > jb || ir < jl || ib < jt)
02560     return false;
02561 
02562   // pre-test
02563   {
02564     Geom::Point sDiff, eDiff;
02565     double slDot, elDot;
02566     double srDot, erDot;
02567     sDiff = ils->pData[lSt].rx - irs->pData[rSt].rx;
02568     eDiff = ils->pData[lEn].rx - irs->pData[rSt].rx;
02569     srDot = cross (sDiff,rdir );
02570     erDot = cross (eDiff,rdir );
02571     if ((srDot >= 0 && erDot >= 0) || (srDot <= 0 && erDot <= 0))
02572       return false;
02573 
02574     sDiff = irs->pData[rSt].rx - ils->pData[lSt].rx;
02575     eDiff = irs->pData[rEn].rx - ils->pData[lSt].rx;
02576     slDot = cross (sDiff,ldir );
02577     elDot = cross (eDiff,ldir);
02578     if ((slDot >= 0 && elDot >= 0) || (slDot <= 0 && elDot <= 0))
02579       return false;
02580 
02581     double slb = slDot - elDot, srb = srDot - erDot;
02582     if (slb < 0)
02583       slb = -slb;
02584     if (srb < 0)
02585       srb = -srb;
02586     if (slb > srb)
02587       {
02588     atx =
02589       (slDot * irs->pData[rEn].rx - elDot * irs->pData[rSt].rx) / (slDot -
02590                                        elDot);
02591       }
02592     else
02593       {
02594     atx =
02595       (srDot * ils->pData[lEn].rx - erDot * ils->pData[lSt].rx) / (srDot -
02596                                        erDot);
02597       }
02598     atL = srDot / (srDot - erDot);
02599     atR = slDot / (slDot - elDot);
02600     return true;
02601   }
02602 
02603   // a mettre en double precision pour des resultats exacts
02604   Geom::Point usvs;
02605   usvs = irs->pData[rSt].rx - ils->pData[lSt].rx;
02606 
02607   // pas sur de l'ordre des coefs de m
02608   Geom::Matrix m(ldir[0], ldir[1],
02609            rdir[0], rdir[1],
02610            0, 0);
02611   double det = m.det();
02612 
02613   double tdet = det * ils->eData[ilb].isqlength * irs->eData[irb].isqlength;
02614 
02615   if (tdet > -0.0001 && tdet < 0.0001)
02616     {               // ces couillons de vecteurs sont colineaires
02617       Geom::Point sDiff, eDiff;
02618       double sDot, eDot;
02619       sDiff = ils->pData[lSt].rx - irs->pData[rSt].rx;
02620       eDiff = ils->pData[lEn].rx - irs->pData[rSt].rx;
02621       sDot = cross (sDiff,rdir );
02622       eDot = cross (eDiff,rdir);
02623 
02624       atx =
02625     (sDot * irs->pData[lEn].rx - eDot * irs->pData[lSt].rx) / (sDot -
02626                                    eDot);
02627       atL = sDot / (sDot - eDot);
02628 
02629       sDiff = irs->pData[rSt].rx - ils->pData[lSt].rx;
02630        eDiff = irs->pData[rEn].rx - ils->pData[lSt].rx;
02631       sDot = cross (sDiff,ldir );
02632       eDot = cross (eDiff,ldir );
02633 
02634       atR = sDot / (sDot - eDot);
02635 
02636       return true;
02637     }
02638 
02639   // plus de colinearite ni d'extremites en commun
02640   m[1] = -m[1];
02641   m[2] = -m[2];
02642   {
02643     double swap = m[0];
02644     m[0] = m[3];
02645     m[3] = swap;
02646   }
02647 
02648   atL = (m[0]* usvs[0] + m[1] * usvs[1]) / det;
02649   atR = -(m[2] * usvs[0] + m[3] * usvs[1]) / det;
02650   atx = ils->pData[lSt].rx + atL * ldir;
02651 
02652 
02653   return true;
02654 }
02655 
02656 bool
02657 Shape::TesteAdjacency (Shape * a, int no, const Geom::Point atx, int nPt,
02658                bool push)
02659 {
02660   if (nPt == a->swsData[no].stPt || nPt == a->swsData[no].enPt)
02661     return false;
02662 
02663   Geom::Point adir, diff, ast, aen, diff1, diff2, diff3, diff4;
02664 
02665   ast = a->pData[a->getEdge(no).st].rx;
02666   aen = a->pData[a->getEdge(no).en].rx;
02667 
02668   adir = a->eData[no].rdx;
02669 
02670   double sle = a->eData[no].length;
02671   double ile = a->eData[no].ilength;
02672 
02673   diff = atx - ast;
02674  
02675   double e = IHalfRound ((cross (diff,adir)) * a->eData[no].isqlength);
02676   if (-3 < e && e < 3)
02677     {
02678       double rad = HalfRound (0.501); // when using single precision, 0.505 is better (0.5 would be the correct value, 
02679                                       // but it produces lots of bugs)
02680       diff1[0] = diff[0] - rad;
02681       diff1[1] = diff[1] - rad;
02682       diff2[0] = diff[0] + rad;
02683       diff2[1] = diff[1] - rad;
02684       diff3[0] = diff[0] + rad;
02685       diff3[1] = diff[1] + rad;
02686       diff4[0] = diff[0] - rad;
02687       diff4[1] = diff[1] + rad;
02688       double di1, di2;
02689       bool adjacent = false;
02690       di1 = cross (diff1,adir);
02691       di2 = cross (diff3,adir);
02692       if ((di1 < 0 && di2 > 0) || (di1 > 0 && di2 < 0))
02693     {
02694       adjacent = true;
02695     }
02696       else
02697     {
02698       di1 = cross ( diff2,adir);
02699       di2 = cross (diff4,adir);
02700       if ((di1 < 0 && di2 > 0) || (di1 > 0 && di2 < 0))
02701         {
02702           adjacent = true;
02703         }
02704     }
02705       if (adjacent)
02706     {
02707       double t = dot (diff, adir);
02708       if (t > 0 && t < sle)
02709         {
02710           if (push)
02711         {
02712           t *= ile;
02713           PushIncidence (a, no, nPt, t);
02714         }
02715           return true;
02716         }
02717     }
02718     }
02719   return false;
02720 }
02721 
02722 void
02723 Shape::CheckAdjacencies (int lastPointNo, int lastChgtPt, Shape * /*shapeHead*/,
02724              int /*edgeHead*/)
02725 {
02726   for (unsigned int cCh = 0; cCh < chgts.size(); cCh++)
02727     {
02728       int chLeN = chgts[cCh].ptNo;
02729       int chRiN = chgts[cCh].ptNo;
02730       if (chgts[cCh].src)
02731     {
02732       Shape *lS = chgts[cCh].src;
02733       int lB = chgts[cCh].bord;
02734       int lftN = lS->swsData[lB].leftRnd;
02735       int rgtN = lS->swsData[lB].rightRnd;
02736       if (lftN < chLeN)
02737         chLeN = lftN;
02738       if (rgtN > chRiN)
02739         chRiN = rgtN;
02740 //                      for (int n=lftN;n<=rgtN;n++) CreateIncidence(lS,lB,n);
02741       for (int n = lftN - 1; n >= lastChgtPt; n--)
02742         {
02743           if (TesteAdjacency (lS, lB, getPoint(n).x, n, false) ==
02744           false)
02745         break;
02746           lS->swsData[lB].leftRnd = n;
02747         }
02748       for (int n = rgtN + 1; n < lastPointNo; n++)
02749         {
02750           if (TesteAdjacency (lS, lB, getPoint(n).x, n, false) ==
02751           false)
02752         break;
02753           lS->swsData[lB].rightRnd = n;
02754         }
02755     }
02756       if (chgts[cCh].osrc)
02757     {
02758       Shape *rS = chgts[cCh].osrc;
02759       int rB = chgts[cCh].obord;
02760       int lftN = rS->swsData[rB].leftRnd;
02761       int rgtN = rS->swsData[rB].rightRnd;
02762       if (lftN < chLeN)
02763         chLeN = lftN;
02764       if (rgtN > chRiN)
02765         chRiN = rgtN;
02766 //                      for (int n=lftN;n<=rgtN;n++) CreateIncidence(rS,rB,n);
02767       for (int n = lftN - 1; n >= lastChgtPt; n--)
02768         {
02769           if (TesteAdjacency (rS, rB, getPoint(n).x, n, false) ==
02770           false)
02771         break;
02772           rS->swsData[rB].leftRnd = n;
02773         }
02774       for (int n = rgtN + 1; n < lastPointNo; n++)
02775         {
02776           if (TesteAdjacency (rS, rB, getPoint(n).x, n, false) ==
02777           false)
02778         break;
02779           rS->swsData[rB].rightRnd = n;
02780         }
02781     }
02782       if (chgts[cCh].lSrc)
02783     {
02784       if (chgts[cCh].lSrc->swsData[chgts[cCh].lBrd].leftRnd < lastChgtPt)
02785         {
02786           Shape *nSrc = chgts[cCh].lSrc;
02787           int nBrd = chgts[cCh].lBrd /*,nNo=chgts[cCh].ptNo */ ;
02788           bool hit;
02789 
02790           do
02791         {
02792           hit = false;
02793           for (int n = chRiN; n >= chLeN; n--)
02794             {
02795               if (TesteAdjacency
02796               (nSrc, nBrd, getPoint(n).x, n, false))
02797             {
02798               if (nSrc->swsData[nBrd].leftRnd < lastChgtPt)
02799                 {
02800                   nSrc->swsData[nBrd].leftRnd = n;
02801                   nSrc->swsData[nBrd].rightRnd = n;
02802                 }
02803               else
02804                 {
02805                   if (n < nSrc->swsData[nBrd].leftRnd)
02806                 nSrc->swsData[nBrd].leftRnd = n;
02807                   if (n > nSrc->swsData[nBrd].rightRnd)
02808                 nSrc->swsData[nBrd].rightRnd = n;
02809                 }
02810               hit = true;
02811             }
02812             }
02813           for (int n = chLeN - 1; n >= lastChgtPt; n--)
02814             {
02815               if (TesteAdjacency
02816               (nSrc, nBrd, getPoint(n).x, n, false) == false)
02817             break;
02818               if (nSrc->swsData[nBrd].leftRnd < lastChgtPt)
02819             {
02820               nSrc->swsData[nBrd].leftRnd = n;
02821               nSrc->swsData[nBrd].rightRnd = n;
02822             }
02823               else
02824             {
02825               if (n < nSrc->swsData[nBrd].leftRnd)
02826                 nSrc->swsData[nBrd].leftRnd = n;
02827               if (n > nSrc->swsData[nBrd].rightRnd)
02828                 nSrc->swsData[nBrd].rightRnd = n;
02829             }
02830               hit = true;
02831             }
02832           if (hit)
02833             {
02834               SweepTree *node =
02835             static_cast < SweepTree * >(nSrc->swsData[nBrd].misc);
02836               if (node == NULL)
02837             break;
02838               node = static_cast < SweepTree * >(node->elem[LEFT]);
02839               if (node == NULL)
02840             break;
02841               nSrc = node->src;
02842               nBrd = node->bord;
02843               if (nSrc->swsData[nBrd].leftRnd >= lastChgtPt)
02844             break;
02845             }
02846         }
02847           while (hit);
02848 
02849         }
02850     }
02851       if (chgts[cCh].rSrc)
02852     {
02853       if (chgts[cCh].rSrc->swsData[chgts[cCh].rBrd].leftRnd < lastChgtPt)
02854         {
02855           Shape *nSrc = chgts[cCh].rSrc;
02856           int nBrd = chgts[cCh].rBrd /*,nNo=chgts[cCh].ptNo */ ;
02857           bool hit;
02858           do
02859         {
02860           hit = false;
02861           for (int n = chLeN; n <= chRiN; n++)
02862             {
02863               if (TesteAdjacency
02864               (nSrc, nBrd, getPoint(n).x, n, false))
02865             {
02866               if (nSrc->swsData[nBrd].leftRnd < lastChgtPt)
02867                 {
02868                   nSrc->swsData[nBrd].leftRnd = n;
02869                   nSrc->swsData[nBrd].rightRnd = n;
02870                 }
02871               else
02872                 {
02873                   if (n < nSrc->swsData[nBrd].leftRnd)
02874                 nSrc->swsData[nBrd].leftRnd = n;
02875                   if (n > nSrc->swsData[nBrd].rightRnd)
02876                 nSrc->swsData[nBrd].rightRnd = n;
02877                 }
02878               hit = true;
02879             }
02880             }
02881           for (int n = chRiN + 1; n < lastPointNo; n++)
02882             {
02883               if (TesteAdjacency
02884               (nSrc, nBrd, getPoint(n).x, n, false) == false)
02885             break;
02886               if (nSrc->swsData[nBrd].leftRnd < lastChgtPt)
02887             {
02888               nSrc->swsData[nBrd].leftRnd = n;
02889               nSrc->swsData[nBrd].rightRnd = n;
02890             }
02891               else
02892             {
02893               if (n < nSrc->swsData[nBrd].leftRnd)
02894                 nSrc->swsData[nBrd].leftRnd = n;
02895               if (n > nSrc->swsData[nBrd].rightRnd)
02896                 nSrc->swsData[nBrd].rightRnd = n;
02897             }
02898               hit = true;
02899             }
02900           if (hit)
02901             {
02902               SweepTree *node =
02903             static_cast < SweepTree * >(nSrc->swsData[nBrd].misc);
02904               if (node == NULL)
02905             break;
02906               node = static_cast < SweepTree * >(node->elem[RIGHT]);
02907               if (node == NULL)
02908             break;
02909               nSrc = node->src;
02910               nBrd = node->bord;
02911               if (nSrc->swsData[nBrd].leftRnd >= lastChgtPt)
02912             break;
02913             }
02914         }
02915           while (hit);
02916         }
02917     }
02918     }
02919 }
02920 
02921 
02922 void Shape::AddChgt(int lastPointNo, int lastChgtPt, Shape * &shapeHead,
02923             int &edgeHead, sTreeChangeType type, Shape * lS, int lB, Shape * rS,
02924             int rB)
02925 {
02926     sTreeChange c;
02927     c.ptNo = lastPointNo;
02928     c.type = type;
02929     c.src = lS;
02930     c.bord = lB;
02931     c.osrc = rS;
02932     c.obord = rB;
02933     chgts.push_back(c);
02934     const int nCh = chgts.size() - 1;
02935 
02936     /* FIXME: this looks like a cut and paste job */
02937 
02938     if (lS) {
02939     SweepTree *lE = static_cast < SweepTree * >(lS->swsData[lB].misc);
02940     if (lE && lE->elem[LEFT]) {
02941         SweepTree *llE = static_cast < SweepTree * >(lE->elem[LEFT]);
02942         chgts[nCh].lSrc = llE->src;
02943         chgts[nCh].lBrd = llE->bord;
02944     } else {
02945         chgts[nCh].lSrc = NULL;
02946         chgts[nCh].lBrd = -1;
02947     }
02948 
02949     if (lS->swsData[lB].leftRnd < lastChgtPt) {
02950         lS->swsData[lB].leftRnd = lastPointNo;
02951         lS->swsData[lB].nextSh = shapeHead;
02952         lS->swsData[lB].nextBo = edgeHead;
02953         edgeHead = lB;
02954         shapeHead = lS;
02955     } else {
02956         int old = lS->swsData[lB].leftRnd;
02957         if (getPoint(old).x[0] > getPoint(lastPointNo).x[0]) {
02958         lS->swsData[lB].leftRnd = lastPointNo;
02959         }
02960     }
02961     if (lS->swsData[lB].rightRnd < lastChgtPt) {
02962         lS->swsData[lB].rightRnd = lastPointNo;
02963     } else {
02964         int old = lS->swsData[lB].rightRnd;
02965         if (getPoint(old).x[0] < getPoint(lastPointNo).x[0])
02966         lS->swsData[lB].rightRnd = lastPointNo;
02967     }
02968     }
02969 
02970     if (rS) {
02971     SweepTree *rE = static_cast < SweepTree * >(rS->swsData[rB].misc);
02972     if (rE->elem[RIGHT]) {
02973         SweepTree *rrE = static_cast < SweepTree * >(rE->elem[RIGHT]);
02974         chgts[nCh].rSrc = rrE->src;
02975         chgts[nCh].rBrd = rrE->bord;
02976     } else {
02977         chgts[nCh].rSrc = NULL;
02978         chgts[nCh].rBrd = -1;
02979     }
02980     
02981     if (rS->swsData[rB].leftRnd < lastChgtPt) {
02982         rS->swsData[rB].leftRnd = lastPointNo;
02983         rS->swsData[rB].nextSh = shapeHead;
02984         rS->swsData[rB].nextBo = edgeHead;
02985         edgeHead = rB;
02986         shapeHead = rS;
02987     } else {
02988         int old = rS->swsData[rB].leftRnd;
02989         if (getPoint(old).x[0] > getPoint(lastPointNo).x[0]) {
02990         rS->swsData[rB].leftRnd = lastPointNo;
02991         }
02992     }
02993     if (rS->swsData[rB].rightRnd < lastChgtPt) {
02994         rS->swsData[rB].rightRnd = lastPointNo;
02995     } else {
02996         int old = rS->swsData[rB].rightRnd;
02997         if (getPoint(old).x[0] < getPoint(lastPointNo).x[0])
02998         rS->swsData[rB].rightRnd = lastPointNo;
02999     }
03000     } else {
03001     SweepTree *lE = static_cast < SweepTree * >(lS->swsData[lB].misc);
03002     if (lE && lE->elem[RIGHT]) {
03003         SweepTree *rlE = static_cast < SweepTree * >(lE->elem[RIGHT]);
03004         chgts[nCh].rSrc = rlE->src;
03005         chgts[nCh].rBrd = rlE->bord;
03006     } else {
03007         chgts[nCh].rSrc = NULL;
03008         chgts[nCh].rBrd = -1;
03009     }
03010     }
03011 }
03012 
03013 // is this a debug function?  It's calling localized "printf" ...
03014 void
03015 Shape::Validate (void)
03016 {
03017   for (int i = 0; i < numberOfPoints(); i++)
03018     {
03019       pData[i].rx = getPoint(i).x;
03020     }
03021   for (int i = 0; i < numberOfEdges(); i++)
03022     {
03023       eData[i].rdx = getEdge(i).dx;
03024     }
03025   for (int i = 0; i < numberOfEdges(); i++)
03026     {
03027       for (int j = i + 1; j < numberOfEdges(); j++)
03028     {
03029         Geom::Point atx;
03030         double   atL, atR;
03031       if (TesteIntersection (this, this, i, j, atx, atL, atR, false))
03032         {
03033           printf ("%i %i  %f %f di=%f %f  dj=%f %f\n", i, j, atx[0],atx[1],getEdge(i).dx[0],getEdge(i).dx[1],getEdge(j).dx[0],getEdge(j).dx[1]);
03034         }
03035     }
03036     }
03037   fflush (stdout);
03038 }
03039 
03040 void
03041 Shape::CheckEdges (int lastPointNo, int lastChgtPt, Shape * a, Shape * b,
03042            BooleanOp mod)
03043 {
03044 
03045   for (unsigned int cCh = 0; cCh < chgts.size(); cCh++)
03046     {
03047       if (chgts[cCh].type == 0)
03048     {
03049       Shape *lS = chgts[cCh].src;
03050       int lB = chgts[cCh].bord;
03051       lS->swsData[lB].curPoint = chgts[cCh].ptNo;
03052     }
03053     }
03054   for (unsigned int cCh = 0; cCh < chgts.size(); cCh++)
03055     {
03056 //              int   chLeN=chgts[cCh].ptNo;
03057 //              int   chRiN=chgts[cCh].ptNo;
03058       if (chgts[cCh].src)
03059     {
03060       Shape *lS = chgts[cCh].src;
03061       int lB = chgts[cCh].bord;
03062       Avance (lastPointNo, lastChgtPt, lS, lB, a, b, mod);
03063     }
03064       if (chgts[cCh].osrc)
03065     {
03066       Shape *rS = chgts[cCh].osrc;
03067       int rB = chgts[cCh].obord;
03068       Avance (lastPointNo, lastChgtPt, rS, rB, a, b, mod);
03069     }
03070       if (chgts[cCh].lSrc)
03071     {
03072       Shape *nSrc = chgts[cCh].lSrc;
03073       int nBrd = chgts[cCh].lBrd;
03074       while (nSrc->swsData[nBrd].leftRnd >=
03075          lastChgtPt /*&& nSrc->swsData[nBrd].doneTo < lastChgtPt */ )
03076         {
03077           Avance (lastPointNo, lastChgtPt, nSrc, nBrd, a, b, mod);
03078 
03079           SweepTree *node =
03080         static_cast < SweepTree * >(nSrc->swsData[nBrd].misc);
03081           if (node == NULL)
03082         break;
03083           node = static_cast < SweepTree * >(node->elem[LEFT]);
03084           if (node == NULL)
03085         break;
03086           nSrc = node->src;
03087           nBrd = node->bord;
03088         }
03089     }
03090       if (chgts[cCh].rSrc)
03091     {
03092       Shape *nSrc = chgts[cCh].rSrc;
03093       int nBrd = chgts[cCh].rBrd;
03094       while (nSrc->swsData[nBrd].rightRnd >=
03095          lastChgtPt /*&& nSrc->swsData[nBrd].doneTo < lastChgtPt */ )
03096         {
03097           Avance (lastPointNo, lastChgtPt, nSrc, nBrd, a, b, mod);
03098 
03099           SweepTree *node =
03100         static_cast < SweepTree * >(nSrc->swsData[nBrd].misc);
03101           if (node == NULL)
03102         break;
03103           node = static_cast < SweepTree * >(node->elem[RIGHT]);
03104           if (node == NULL)
03105         break;
03106           nSrc = node->src;
03107           nBrd = node->bord;
03108         }
03109     }
03110     }
03111 }
03112 
03113 void
03114 Shape::Avance (int lastPointNo, int lastChgtPt, Shape * lS, int lB, Shape * /*a*/,
03115            Shape * b, BooleanOp mod)
03116 {
03117   double dd = HalfRound (1);
03118   bool avoidDiag = false;
03119 //      if ( lastChgtPt > 0 && pts[lastChgtPt-1].y+dd == pts[lastChgtPt].y ) avoidDiag=true;
03120 
03121   bool direct = true;
03122   if (lS == b && (mod == bool_op_diff || mod == bool_op_symdiff))
03123     direct = false;
03124   int lftN = lS->swsData[lB].leftRnd;
03125   int rgtN = lS->swsData[lB].rightRnd;
03126   if (lS->swsData[lB].doneTo < lastChgtPt)
03127     {
03128       int lp = lS->swsData[lB].curPoint;
03129       if (lp >= 0 && getPoint(lp).x[1] + dd == getPoint(lastChgtPt).x[1])
03130     avoidDiag = true;
03131       if (lS->eData[lB].rdx[1] == 0)
03132     {
03133       // tjs de gauche a droite et pas de diagonale
03134       if (lS->eData[lB].rdx[0] >= 0)
03135         {
03136           for (int p = lftN; p <= rgtN; p++)
03137         {
03138           DoEdgeTo (lS, lB, p, direct, true);
03139           lp = p;
03140         }
03141         }
03142       else
03143         {
03144           for (int p = lftN; p <= rgtN; p++)
03145         {
03146           DoEdgeTo (lS, lB, p, direct, false);
03147           lp = p;
03148         }
03149         }
03150     }
03151       else if (lS->eData[lB].rdx[1] > 0)
03152     {
03153       if (lS->eData[lB].rdx[0] >= 0)
03154         {
03155 
03156           for (int p = lftN; p <= rgtN; p++)
03157         {
03158           if (avoidDiag && p == lftN && getPoint(lftN).x[0] == getPoint(lp).x[0] + dd)
03159             {
03160               if (lftN > 0 && lftN - 1 >= lastChgtPt
03161               && getPoint(lftN - 1).x[0] == getPoint(lp).x[0])
03162             {
03163               DoEdgeTo (lS, lB, lftN - 1, direct, true);
03164               DoEdgeTo (lS, lB, lftN, direct, true);
03165             }
03166               else
03167             {
03168               DoEdgeTo (lS, lB, lftN, direct, true);
03169             }
03170             }
03171           else
03172             {
03173               DoEdgeTo (lS, lB, p, direct, true);
03174             }
03175           lp = p;
03176         }
03177         }
03178       else
03179         {
03180 
03181           for (int p = rgtN; p >= lftN; p--)
03182         {
03183           if (avoidDiag && p == rgtN && getPoint(rgtN).x[0] == getPoint(lp).x[0] - dd)
03184             {
03185               if (rgtN < numberOfPoints() && rgtN + 1 < lastPointNo
03186               && getPoint(rgtN + 1).x[0] == getPoint(lp).x[0])
03187             {
03188               DoEdgeTo (lS, lB, rgtN + 1, direct, true);
03189               DoEdgeTo (lS, lB, rgtN, direct, true);
03190             }
03191               else
03192             {
03193               DoEdgeTo (lS, lB, rgtN, direct, true);
03194             }
03195             }
03196           else
03197             {
03198               DoEdgeTo (lS, lB, p, direct, true);
03199             }
03200           lp = p;
03201         }
03202         }
03203     }
03204       else
03205     {
03206       if (lS->eData[lB].rdx[0] >= 0)
03207         {
03208 
03209           for (int p = rgtN; p >= lftN; p--)
03210         {
03211           if (avoidDiag && p == rgtN && getPoint(rgtN).x[0] == getPoint(lp).x[0] - dd)
03212             {
03213               if (rgtN < numberOfPoints() && rgtN + 1 < lastPointNo
03214               && getPoint(rgtN + 1).x[0] == getPoint(lp).x[0])
03215             {
03216               DoEdgeTo (lS, lB, rgtN + 1, direct, false);
03217               DoEdgeTo (lS, lB, rgtN, direct, false);
03218             }
03219               else
03220             {
03221               DoEdgeTo (lS, lB, rgtN, direct, false);
03222             }
03223             }
03224           else
03225             {
03226               DoEdgeTo (lS, lB, p, direct, false);
03227             }
03228           lp = p;
03229         }
03230         }
03231       else
03232         {
03233 
03234           for (int p = lftN; p <= rgtN; p++)
03235         {
03236           if (avoidDiag && p == lftN && getPoint(lftN).x[0] == getPoint(lp).x[0] + dd)
03237             {
03238               if (lftN > 0 && lftN - 1 >= lastChgtPt
03239               && getPoint(lftN - 1).x[0] == getPoint(lp).x[0])
03240             {
03241               DoEdgeTo (lS, lB, lftN - 1, direct, false);
03242               DoEdgeTo (lS, lB, lftN, direct, false);
03243             }
03244               else
03245             {
03246               DoEdgeTo (lS, lB, lftN, direct, false);
03247             }
03248             }
03249           else
03250             {
03251               DoEdgeTo (lS, lB, p, direct, false);
03252             }
03253           lp = p;
03254         }
03255         }
03256     }
03257       lS->swsData[lB].curPoint = lp;
03258     }
03259   lS->swsData[lB].doneTo = lastPointNo - 1;
03260 }
03261 
03262 void
03263 Shape::DoEdgeTo (Shape * iS, int iB, int iTo, bool direct, bool sens)
03264 {
03265   int lp = iS->swsData[iB].curPoint;
03266   int ne = -1;
03267   if (sens)
03268     {
03269       if (direct)
03270     ne = AddEdge (lp, iTo);
03271       else
03272     ne = AddEdge (iTo, lp);
03273     }
03274   else
03275     {
03276       if (direct)
03277     ne = AddEdge (iTo, lp);
03278       else
03279     ne = AddEdge (lp, iTo);
03280     }
03281   if (ne >= 0 && _has_back_data)
03282     {
03283       ebData[ne].pathID = iS->ebData[iB].pathID;
03284       ebData[ne].pieceID = iS->ebData[iB].pieceID;
03285       if (iS->eData[iB].length < 0.00001)
03286     {
03287       ebData[ne].tSt = ebData[ne].tEn = iS->ebData[iB].tSt;
03288     }
03289       else
03290     {
03291       double bdl = iS->eData[iB].ilength;
03292     Geom::Point bpx = iS->pData[iS->getEdge(iB).st].rx;
03293       Geom::Point bdx = iS->eData[iB].rdx;
03294       Geom::Point psx = getPoint(getEdge(ne).st).x;
03295       Geom::Point pex = getPoint(getEdge(ne).en).x;
03296         Geom::Point psbx=psx-bpx;
03297         Geom::Point pebx=pex-bpx;
03298       double pst = dot(psbx,bdx) * bdl;
03299       double pet = dot(pebx,bdx) * bdl;
03300       pst = iS->ebData[iB].tSt * (1 - pst) + iS->ebData[iB].tEn * pst;
03301       pet = iS->ebData[iB].tSt * (1 - pet) + iS->ebData[iB].tEn * pet;
03302       ebData[ne].tEn = pet;
03303       ebData[ne].tSt = pst;
03304     }
03305     }
03306   iS->swsData[iB].curPoint = iTo;
03307   if (ne >= 0)
03308     {
03309       int cp = iS->swsData[iB].firstLinkedPoint;
03310       swsData[ne].firstLinkedPoint = iS->swsData[iB].firstLinkedPoint;
03311       while (cp >= 0)
03312     {
03313       pData[cp].askForWindingB = ne;
03314       cp = pData[cp].nextLinkedPoint;
03315     }
03316       iS->swsData[iB].firstLinkedPoint = -1;
03317     }
03318 }