ShapeSweep.cpp revision c0537dcfe264414d52ad86579d57cb0cb2183dcb
/*
* nlivarot
*
* Created by fred on Thu Jun 19 2003.
*
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <glib.h>
#include "Shape.h"
#include "livarot/sweep-event-queue.h"
#include "livarot/sweep-tree-list.h"
#include "livarot/sweep-tree.h"
//int doDebug=0;
/*
* El Intersector.
* algorithm: 1) benley ottman to get intersections of all the polygon's edges
* 2) rounding of the points of the polygon, Hooby's algorithm
* 3) DFS with clockwise choice of the edge to compute the windings
* 4) choose edges according to winding numbers and fill rule
* some additional nastyness: step 2 needs a seed winding number for the upper-left point of each
* connex subgraph of the graph. computing these brutally is O(n^3): baaaad. so during the sweeping in 1)
* we keep for each point the edge of the resulting graph (not the original) that lies just on its left;
* when the time comes for the point to get its winding number computed, that edge must have been treated,
* because its upper end lies above the aforementioned point, meaning we know the winding number of the point.
* only, there is a catch: since we're sweeping the polygon, the edge we want to link the point to has not yet been
* added (that would be too easy...). so the points are put on a linked list on the original shape's edge, and the list
* is flushed when the edge is added.
* rounding: to do the rounding, we need to find which edges cross the surrounding of the rounded points (at
* each sweepline position). grunt method tries all combination of "rounded points in the sweepline"x"edges crossing
* the sweepline". That's bad (and that's what polyboolean does, if i am not mistaken). so for each point
* rounded in a given sweepline, keep immediate left and right edges at the time the point is treated.
* when edges/points crossing are searched, walk the edge list (in the sweepline at the end of the batch) starting
* from the rounded points' left and right from that time. may sound strange, but it works because edges that
* end or start in the batch have at least one end in the batch.
* all these are the cause of the numerous linked lists of points and edges maintained in the sweeping
*/
void
Shape::ResetSweep (void)
{
MakePointData (true);
MakeEdgeData (true);
MakeSweepSrcData (true);
}
void
Shape::CleanupSweep (void)
{
MakePointData (false);
MakeEdgeData (false);
MakeSweepSrcData (false);
}
void
Shape::ForceToPolygon (void)
{
}
int
{
Reset (0, 0);
return 0;
if (directedEulerian(a) == false)
return shape_input_err;
if (numberOfPoints() > maxPt)
{
maxPt = numberOfPoints();
if (_has_points_data) {
_point_data_initialised = false;
_bbox_up_to_date = false;
}
}
if (numberOfEdges() > maxAr)
{
maxAr = numberOfEdges();
if (_has_edges_data)
if (_has_sweep_src_data)
if (_has_sweep_dest_data)
if (_has_raster_data)
}
MakePointData (true);
MakeEdgeData (true);
MakeSweepDestData (true);
for (int i = 0; i < numberOfPoints(); i++) {
}
for (int i = 0; i < a->numberOfEdges(); i++)
{
}
_need_edges_sorting = true;
// Plot(341,56,8,400,400,true,true,false,true);
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
MakePointData (false);
MakeEdgeData (false);
MakeSweepDestData (false);
if (directedEulerian(this) == false)
{
// printf( "pas euclidian2");
return shape_euler_err;
}
return 0;
}
int
{
Reset (0, 0);
return 0;
}
g_warning ("Shape error in ConvertToShape: directedEulerian(a) == false\n");
return shape_input_err;
}
a->ResetSweep();
}
}
MakePointData(true);
MakeEdgeData(true);
MakeSweepSrcData(true);
MakeSweepDestData(true);
a->initialisePointData();
a->initialiseEdgeData();
a->SortPointsRounded();
int lastChgtPt = 0;
int edgeHead = -1;
int curAPt = 0;
int nPt = -1;
bool isIntersection = false;
{
{
/* FIXME: could just be pop? */
isIntersection = true;
}
else
{
ptSh = a;
isIntersection = false;
}
}
else
{
ptSh = a;
isIntersection = false;
}
if (isIntersection == false)
{
continue;
}
int lastPointNo = -1;
{
while (curSh)
{
}
{
{
{
}
else
{
}
}
{
{
}
else
{
}
}
}
for (int i = lastChgtPt; i < lastI; i++) {
if (pData[i].askForWindingS) {
}
}
if (lastI < lastPointNo) {
}
lastPointNo = lastI;
edgeHead = -1;
}
if (isIntersection)
{
// printf("(%i %i [%i %i]) ",intersL->bord,intersR->bord,intersL->startPoint,intersR->startPoint);
}
else
{
int cb;
{
{
nbUp++;
}
{
nbDn++;
}
}
if (nbDn <= 0)
{
upNo = -1;
}
{
upNo = -1;
}
bool doWinding = true;
if (nbUp > 0)
{
{
{
{
{
}
else
{
NULL, -1);
{
onLeftB =
(static_cast <
onLeftS =
(static_cast <
}
{
onRightB =
(static_cast <
onRightS =
(static_cast <
}
{
misc;
nPt))
{
}
else
{
{
}
else
{
}
}
}
}
}
}
}
}
// traitement du "upNo devient dnNo"
if (dnNo >= 0)
{
if (upNo >= 0)
{
}
else
{
if (doWinding)
{
if (myLeft)
{
}
else
{
}
doWinding = false;
}
}
}
if (nbDn > 1)
{ // si nbDn == 1 , alors dnNo a deja ete traite
{
{
{
nPt, true);
if (doWinding)
{
if (myLeft)
{
}
else
{
}
doWinding = false;
}
-1);
}
}
}
}
}
}
{
while (curSh)
{
}
{
{
{
}
else
{
}
}
{
{
}
else
{
}
}
}
for (int i = lastChgtPt; i < lastI; i++)
{
if (pData[i].askForWindingS)
{
}
}
edgeHead = -1;
}
// Plot (98.0, 112.0, 8.0, 400.0, 400.0, true, true, true, true);
// Plot(200.0,200.0,2.0,400.0,400.0,true,true,true,true);
// AssemblePoints(a);
// GetAdjacencies(a);
// MakeAretes(a);
// Plot (98.0, 112.0, 8.0, 400.0, 400.0, true, true, true, true);
for (int i = 0; i < numberOfPoints(); i++)
{
}
// Validate();
_need_edges_sorting = true;
if ( directed == fill_justDont ) {
SortEdges();
} else {
GetWindings (a);
}
// Plot (98.0, 112.0, 8.0, 400.0, 400.0, true, true, true, true);
// if ( doDebug ) {
// a->CalcBBox();
// a->Plot(a->leftX,a->topY,32.0,0.0,0.0,true,true,true,true,"orig.svg");
// Plot(a->leftX,a->topY,32.0,0.0,0.0,true,true,true,true,"winded.svg");
// }
if (directed == fill_positive)
{
if (invert)
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
}
else
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
}
}
else if (directed == fill_nonZero)
{
if (invert)
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
}
{
Inverse (i);
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
}
else
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
}
{
Inverse (i);
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
}
}
else if (directed == fill_oddEven)
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
} else if ( directed == fill_justDont ) {
for (int i=0;i<numberOfEdges();i++) {
SubEdge(i);
i--;
} else {
}
}
}
// Plot(200.0,200.0,2.0,400.0,400.0,true,true,true,true);
delete sTree;
delete sEvts;
MakePointData (false);
MakeEdgeData (false);
MakeSweepSrcData (false);
MakeSweepDestData (false);
a->CleanupSweep ();
return 0;
}
// technically it's just a ConvertToShape() on 2 polygons at the same time, and different rules
// for choosing the edges according to their winding numbers.
// probably one of the biggest function i ever wrote.
int
{
return shape_input_err;
Reset (0, 0);
return 0;
return 0;
if ( mod == bool_op_cut ) {
} else if ( mod == bool_op_slice ) {
} else {
if (a->type != shape_polygon)
return shape_input_err;
if (b->type != shape_polygon)
return shape_input_err;
}
a->ResetSweep ();
b->ResetSweep ();
}
}
MakePointData (true);
MakeEdgeData (true);
MakeSweepSrcData (true);
MakeSweepDestData (true);
if (a->hasBackData () && b->hasBackData ())
{
MakeBackData (true);
}
else
{
MakeBackData (false);
}
a->initialisePointData();
b->initialisePointData();
a->initialiseEdgeData();
b->initialiseEdgeData();
a->SortPointsRounded ();
b->SortPointsRounded ();
double lastChange =
int lastChgtPt = 0;
int edgeHead = -1;
int curAPt = 0;
int curBPt = 0;
{
/* for (int i=0;i<sEvts.nbEvt;i++) {
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
}
// cout << endl;
if ( sTree.racine ) {
SweepTree* ct=static_cast <SweepTree*> (sTree.racine->Leftmost());
while ( ct ) {
printf("%i %i [%i\n",ct->bord,ct->startPoint,(ct->src==a)?1:0);
ct=static_cast <SweepTree*> (ct->elem[RIGHT]);
}
}
printf("\n");*/
int nPt = -1;
bool isIntersection = false;
{
if (curAPt < a->numberOfPoints())
{
if (curBPt < b->numberOfPoints())
{
{
{
/* FIXME: could be pop? */
isIntersection = true;
}
else
{
ptSh = a;
isIntersection = false;
}
}
else
{
{
/* FIXME: could be pop? */
isIntersection = true;
}
else
{
ptSh = b;
isIntersection = false;
}
}
}
else
{
{
/* FIXME: could be pop? */
isIntersection = true;
}
else
{
ptSh = a;
isIntersection = false;
}
}
}
else
{
{
/* FIXME: could be pop? */
isIntersection = true;
}
else
{
ptSh = b;
isIntersection = false;
}
}
}
else
{
if (curAPt < a->numberOfPoints())
{
if (curBPt < b->numberOfPoints())
{
{
ptSh = a;
}
else
{
ptSh = b;
}
}
else
{
ptSh = a;
}
}
else
{
ptSh = b;
}
isIntersection = false;
}
if (isIntersection == false)
{
continue;
}
int lastPointNo = -1;
{
while (curSh)
{
}
{
{
{
}
else
{
}
}
{
{
}
else
{
}
}
}
for (int i = lastChgtPt; i < lastI; i++)
{
if (pData[i].askForWindingS)
{
pData[i].nextLinkedPoint =
}
}
if (lastI < lastPointNo)
{
}
lastPointNo = lastI;
edgeHead = -1;
}
if (isIntersection)
{
// les 2 events de part et d'autre de l'intersection
// (celui de l'intersection a deja ete depile)
}
else
{
int cb;
{
{
nbUp++;
}
{
nbDn++;
}
}
if (nbDn <= 0)
{
upNo = -1;
}
{
upNo = -1;
}
// upNo=-1;
bool doWinding = true;
if (nbUp > 0)
{
{
{
{
{
}
else
{
NULL, -1);
{
onLeftB =
(static_cast <
onLeftS =
(static_cast <
}
{
onRightB =
(static_cast <
onRightS =
(static_cast <
}
{
misc;
// SweepTree* onRight=(SweepTree*)onRightS->swsData[onRightB].misc;
nPt))
{
}
else
{
{
}
else
{
}
}
}
}
}
}
}
}
// traitement du "upNo devient dnNo"
if (dnNo >= 0)
{
if (upNo >= 0)
{
}
else
{
if (doWinding)
{
if (myLeft)
{
}
else
{
}
doWinding = false;
}
}
}
if (nbDn > 1)
{ // si nbDn == 1 , alors dnNo a deja ete traite
{
{
{
// node->Insert(sTree,*sEvts,this,lastPointNo,true);
nPt, true);
if (doWinding)
{
if (myLeft)
{
}
else
{
}
doWinding = false;
}
-1);
}
}
}
}
}
}
{
while (curSh)
{
}
/* FIXME: this kind of code seems to appear frequently */
{
{
{
}
else
{
}
}
{
{
}
else
{
}
}
}
for (int i = lastChgtPt; i < lastI; i++)
{
if (pData[i].askForWindingS)
{
}
}
edgeHead = -1;
}
// Plot(190,70,6,400,400,true,false,true,true);
if ( mod == bool_op_cut ) {
// dupliquer les aretes de la coupure
int i=numberOfEdges()-1;
for (;i>=0;i--) {
// on duplique
// lui donner les firstlinkedpoitn si besoin
while (cp >= 0) {
}
}
}
}
} else if ( mod == bool_op_slice ) {
} else {
AssembleAretes ();
}
for (int i = 0; i < numberOfPoints(); i++)
{
}
_need_edges_sorting = true;
if ( mod == bool_op_slice ) {
} else {
GetWindings (a, b, mod, false);
}
// Plot(190,70,6,400,400,true,true,true,true);
if (mod == bool_op_symdiff)
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
}
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
}
else if (mod == bool_op_inters)
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
} else if ( mod == bool_op_cut ) {
// inverser les aretes de la coupe au besoin
for (int i=0;i<numberOfEdges();i++) {
if ( i < numberOfEdges()-1 ) {
// decaler les askForWinding
while (cp >= 0) {
}
}
// SubEdge(i);
i--;
Inverse(i);
}
}
}
} else if ( mod == bool_op_slice ) {
// supprimer les aretes de la coupe
int i=numberOfEdges()-1;
for (;i>=0;i--) {
SubEdge(i);
}
}
}
else
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
}
{
Inverse (i);
}
else
{
SubEdge (i);
i--;
}
}
}
delete sTree;
delete sEvts;
if ( mod == bool_op_cut ) {
// on garde le askForWinding
} else {
MakePointData (false);
}
MakeEdgeData (false);
MakeSweepSrcData (false);
MakeSweepDestData (false);
a->CleanupSweep ();
b->CleanupSweep ();
if (directedEulerian(this) == false)
{
// printf( "pas euclidian2");
return shape_euler_err;
}
return 0;
}
// frontend to the TesteIntersection() below
{
return;
}
double atl;
double atr;
}
}
// a crucial piece of code: computing intersections between segments
bool
Shape::TesteIntersection (SweepTree * iL, SweepTree * iR, Geom::Point &atx, double &atL, double &atR, bool onlyDiff)
{
// first, a round of checks to quickly dismiss edge which obviously dont intersect,
// such as having disjoint bounding boxes
{
}
else
{
}
{
}
else
{
}
{
{
return false;
return false;
}
else
{
return false;
return false;
}
}
else
{
{
return false;
return false;
}
else
{
return false;
return false;
}
}
// ang*=iL->src->eData[iL->bord].isqlength;
// ang*=iR->src->eData[iR->bord].isqlength;
if (ang <= 0) return false; // edges in opposite directions: <-left ... right ->
// they can't intersect
// d'abord tester les bords qui partent d'un meme point
{
return false; // c'est juste un doublon
return true; // l'ordre est mauvais
}
return false; // rien a faire=ils vont terminer au meme endroit
// tester si on est dans une intersection multiple
return false;
// on reprend les vrais points
// compute intersection (if there is one)
// Boissonat anr Preparata said in one paper that double precision floats were sufficient for get single precision
// coordinates for the intersection, if the endpoints are single precision. i hope they're right...
{
{
if (srDot == 0)
{
{
atL = 0;
return true;
}
else
{
return false;
}
}
else if (erDot == 0)
{
{
atL = 1;
return true;
}
else
{
return false;
}
}
{
{
{
{
atL = 0;
return true;
}
}
else
{
{
atL = 1;
return true;
}
}
}
}
{
{
{
{
atL = 0;
return true;
}
}
else
{
{
atL = 1;
return true;
}
}
}
}
return false;
}
{
if (slDot == 0)
{
{
atR = 0;
return true;
}
else
{
return false;
}
}
else if (elDot == 0)
{
{
atR = 1;
return true;
}
else
{
return false;
}
}
{
{
{
{
atR = 0;
return true;
}
}
else
{
{
atR = 1;
return true;
}
}
}
}
{
{
{
{
atR = 0;
return true;
}
}
else
{
{
atR = 1;
return true;
}
}
}
}
return false;
}
/* double slb=slDot-elDot,srb=srDot-erDot;
if ( slb < 0 ) slb=-slb;
if ( srb < 0 ) srb=-srb;*/
{
atx =
}
else
{
atx =
}
return true;
}
return true;
}
int
{
return -1;
{
iData =
}
int n = nbInc++;
return n;
}
int
{
}
int
{
return 0;
{
}
else
{
}
return 0;
}
int
{
for (int i = 0; i < numberOfEdges(); i++)
{
{
continue;
continue;
}
else
{
continue;
continue;
}
{
continue;
continue;
else
continue;
}
{
continue;
continue;
else
continue;
}
{
continue;
}
else
{
continue;
}
if (cote == 0)
continue;
if (cote < 0)
{
}
else
{
}
}
}
// merging duplicate points and edges
int
{
// SortPoints(st,en-1);
SortPointsByOldInd (st, en - 1); // SortPointsByOldInd() is required here, because of the edges we have
// associated with the point for later computation of winding numbers.
// specifically, we need the first point we treated, it's the only one with a valid
// associated edge (man, that was a nice bug).
if (i > st && getPoint(i - 1).x[0] == getPoint(i).x[0] && getPoint(i - 1).x[1] == getPoint(i).x[1]) {
} else {
// meme bord, c bon
} else {
// meme point, mais pas le meme bord: ouille!
// il faut prendre le bord le plus a gauche
// en pratique, n'arrive que si 2 maxima sont dans la meme case -> le mauvais choix prend une arete incidente
// au bon choix
// printf("doh");
}
}
lastI--;
} else {
}
}
}
return lastI;
}
return en;
}
void
{
if (hasPoints())
{
for (int i = 0; i < a->numberOfEdges(); i++)
{
}
for (int i = 0; i < nbInc; i++)
}
}
void
{
}
for (int i = 0; i < numberOfPoints(); i++) {
bool doublon=false;
if ( directed == fill_justDont ) {
if ( doublon ) {
}
}
}
}
} else {
}
if ( doublon ) {
} else {
}
while (cp >= 0) {
}
} else {
}
}
}
DisconnectEnd (cc);
if (numberOfEdges() > 1) {
while (cp >= 0) {
}
}
}
}
} else {
int cb;
int cc;
bool doublon=false;
if ( directed == fill_justDont ) {
if ( doublon ) {
doublon=false;
doublon=false;
doublon=false;
}
}
}
}
} else {
}
if ( doublon ) {
// if (cc != cb && Other (i, cc) == other) {
// doublon
} else {
}
while (cp >= 0) {
}
} else {
}
}
}
DisconnectEnd (cc);
if (numberOfEdges() > 1) {
while (cp >= 0) {
}
}
}
}
}
}
}
}
}
if ( directed == fill_justDont ) {
for (int i = 0; i < numberOfEdges(); i++) {
// SubEdge(i);
// i--;
} else {
}
}
} else {
for (int i = 0; i < numberOfEdges(); i++) {
// SubEdge(i);
// i--;
} else {
}
}
}
}
void
{
// preparation du parcours
for (int i = 0; i < numberOfEdges(); i++)
{
}
// chainage
SortEdges ();
int searchInd = 0;
int lastPtUsed = 0;
do
{
int startBord = -1;
int outsideW = 0;
{
int fi = 0;
{
break;
}
if (fi < numberOfPoints())
{
if (bestB >= 0)
{
if (fi == 0)
{
outsideW = 0;
}
else
{
if (brutal)
{
}
else
{
}
}
// on se contente d'inverser
} else {
// on passe le askForWinding (sinon ca va rester startBord)
}
}
}
}
}
}
if (startBord >= 0)
{
// parcours en profondeur pour mettre les leF et riF a leurs valeurs
// if ( doDebug ) printf("part de %d\n",startBord);
bool curDir = true;
do
{
int cPt;
if (curDir)
else
// if ( doDebug ) printf("de curBord= %d avec leF= %d et riF= %d -> ",curBord,swdData[curBord].leW,swdData[curBord].riW);
do
{
int nnb = -1;
{
}
else
{
}
{
// cul-de-sac
nb = -1;
break;
}
}
{
// retour en arriere
int oPt;
if (curDir)
else
// if ( doDebug ) printf("retour vers %d\n",curBord);
if (curBord < 0)
break;
curDir = true;
else
curDir = false;
}
else
{
{
}
else
{
}
// if ( doDebug ) printf("suite %d\n",curBord);
curDir = false;
else
curDir = true;
}
}
while (1 /*swdData[curBord].precParc >= 0 */ );
// fin du cas non-oriente
}
}
while (lastPtUsed < numberOfPoints());
// fflush(stdout);
}
bool
bool /*onlyDiff*/)
{
{
return false;
}
{
return false;
}
{
}
{
}
{
}
{
}
return false;
// pre-test
{
return false;
return false;
if (slb < 0)
if (srb < 0)
{
atx =
elDot);
}
else
{
atx =
erDot);
}
return true;
}
// a mettre en double precision pour des resultats exacts
// pas sur de l'ordre des coefs de m
0, 0);
{ // ces couillons de vecteurs sont colineaires
atx =
eDot);
return true;
}
// plus de colinearite ni d'extremites en commun
m[1] = -m[1];
m[2] = -m[2];
{
double swap = m[0];
m[0] = m[3];
m[3] = swap;
}
return true;
}
bool
bool push)
{
return false;
if (-3 < e && e < 3)
{
double rad = HalfRound (0.501); // when using single precision, 0.505 is better (0.5 would be the correct value,
// but it produces lots of bugs)
bool adjacent = false;
{
adjacent = true;
}
else
{
{
adjacent = true;
}
}
if (adjacent)
{
if (t > 0 && t < sle)
{
if (push)
{
t *= ile;
}
return true;
}
}
}
return false;
}
void
int /*edgeHead*/)
{
{
{
// for (int n=lftN;n<=rgtN;n++) CreateIncidence(lS,lB,n);
{
false)
break;
}
{
false)
break;
}
}
{
// for (int n=lftN;n<=rgtN;n++) CreateIncidence(rS,rB,n);
{
false)
break;
}
{
false)
break;
}
}
{
{
bool hit;
do
{
hit = false;
{
if (TesteAdjacency
{
{
}
else
{
}
hit = true;
}
}
{
if (TesteAdjacency
break;
{
}
else
{
}
hit = true;
}
if (hit)
{
break;
break;
break;
}
}
while (hit);
}
}
{
{
bool hit;
do
{
hit = false;
{
if (TesteAdjacency
{
{
}
else
{
}
hit = true;
}
}
{
if (TesteAdjacency
break;
{
}
else
{
}
hit = true;
}
if (hit)
{
break;
break;
break;
}
}
while (hit);
}
}
}
}
int rB)
{
sTreeChange c;
c.ptNo = lastPointNo;
/* FIXME: this looks like a cut and paste job */
if (lS) {
} else {
}
} else {
}
}
} else {
}
}
if (rS) {
} else {
}
} else {
}
}
} else {
}
} else {
} else {
}
}
}
// is this a debug function? It's calling localized "printf" ...
void
{
for (int i = 0; i < numberOfPoints(); i++)
{
}
for (int i = 0; i < numberOfEdges(); i++)
{
}
for (int i = 0; i < numberOfEdges(); i++)
{
for (int j = i + 1; j < numberOfEdges(); j++)
{
{
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]);
}
}
}
}
void
{
{
{
}
}
{
// int chLeN=chgts[cCh].ptNo;
// int chRiN=chgts[cCh].ptNo;
{
}
{
}
{
lastChgtPt /*&& nSrc->swsData[nBrd].doneTo < lastChgtPt */ )
{
break;
break;
}
}
{
lastChgtPt /*&& nSrc->swsData[nBrd].doneTo < lastChgtPt */ )
{
break;
break;
}
}
}
}
void
{
bool avoidDiag = false;
// if ( lastChgtPt > 0 && pts[lastChgtPt-1].y+dd == pts[lastChgtPt].y ) avoidDiag=true;
bool direct = true;
direct = false;
{
avoidDiag = true;
{
// tjs de gauche a droite et pas de diagonale
{
{
lp = p;
}
}
else
{
{
lp = p;
}
}
}
{
{
{
{
{
}
else
{
}
}
else
{
}
lp = p;
}
}
else
{
{
{
{
}
else
{
}
}
else
{
}
lp = p;
}
}
}
else
{
{
{
{
{
}
else
{
}
}
else
{
}
lp = p;
}
}
else
{
{
{
{
}
else
{
}
}
else
{
}
lp = p;
}
}
}
}
}
void
{
int ne = -1;
if (sens)
{
if (direct)
else
}
else
{
if (direct)
else
}
if (ne >= 0 && _has_back_data)
{
{
}
else
{
}
}
if (ne >= 0)
{
while (cp >= 0)
{
}
}
}