logo

Inkscape

  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files

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     NR::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       NR::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