1
/************************************************************************************
2
TerraLib - a library for developing GIS applications.
3
Copyright � 2001-2004 INPE and Tecgraf/PUC-Rio.
5
This code is part of the TerraLib library.
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Lesser General Public
8
License as published by the Free Software Foundation; either
9
version 2.1 of the License, or (at your option) any later version.
11
You should have received a copy of the GNU Lesser General Public
12
License along with this library.
14
The authors reassure the license terms regarding the warranties.
15
They specifically disclaim any warranties, including, but not limited to,
16
the implied warranties of merchantability and fitness for a particular purpose.
17
The library provided hereunder is on an "as is" basis, and the authors have no
18
obligation to provide maintenance, support, updates, enhancements, or modifications.
19
In no event shall INPE and Tecgraf / PUC-Rio be held liable to any party for direct,
20
indirect, special, incidental, or consequential damages arising out of the use
21
of this library and its documentation.
22
*************************************************************************************/
24
#include "TeOverlay.h"
25
#include "TeIntersector.h"
26
#include "TeGeometryAlgorithms.h"
27
#include "TeFragmentation.h"
36
//---------------- Auxiliary structure ----------------//
39
bool operator()(const TeCoord2D& c1, const TeCoord2D& c2) const
41
if(TeGeometryAlgorithmsPrecision::IsGreater(c2.x_, c1.x_))
44
if(TeGeometryAlgorithmsPrecision::IsGreater(c1.x_, c2.x_))
47
if(TeGeometryAlgorithmsPrecision::IsGreater(c2.y_, c1.y_))
54
typedef multimap<TeCoord2D, pair<unsigned int, TeLine2D>, xyOrder> TeLineIndex;
58
inline void TeRemoveDuplicatedSegments(TeLine2D& l)
60
bool hasDuplicated = false;
62
for(unsigned int i = 1; i < l.size() - 1; ++i)
63
if(TeEquals(l[i - 1], l[i + 1]))
70
TeRemoveDuplicatedCoordinates(l);
75
void TeClonePolygonSet(const TePolygonSet& pSetIn, TePolygonSet& pSetOut)
77
for(unsigned int i = 0; i < pSetIn.size(); ++i)
80
for(unsigned int j = 0; j < pSetIn[i].size(); ++j)
84
for(unsigned int k = 0; k < pSetIn[i][j].size(); ++k)
85
l.add(pSetIn[i][j][k]);
87
TeRemoveDuplicatedCoordinates(l);
89
TeRemoveDuplicatedSegments(l);
100
void TeCloneLineSet(const TeLineSet& lSetIn, TeLineSet& lSetOut)
102
for(unsigned int i = 0; i < lSetIn.size(); ++i)
106
for(unsigned int j = 0; j < lSetIn[i].size(); ++j)
109
TeRemoveDuplicatedCoordinates(l);
116
// Verifica qual opera��o a realizar e j� coloca as fronteiras dos pol�gonos na ordem correta e caso n�o seja necess�rio opera��o, ele j� retorna o resultado
117
TePolygonSet TeChooseOperation(const short& operation, TePolygonSet& redPols, TePolygonSet& bluePols, short& locationRedFragments, short& locationBlueFragments)
125
// Intersection gets all fragments from red polygon wich are
126
// inside the blue polygon and the blue fragments that are inside
128
case TeINTERSECTION: if(TeDisjoint(redPols.box(), bluePols.box()))
131
// Need to reverse orientation
132
for(i = 0; i < bluePols.size(); ++i)
134
if(TeOrientation(bluePols[i][0]) == TeCOUNTERCLOCKWISE)
135
reverse(bluePols[i][0].begin(), bluePols[i][0].end());
137
for(unsigned int j = 1; j < bluePols[i].size(); ++j)
139
if(TeOrientation(bluePols[i][j]) == TeCLOCKWISE)
140
reverse(bluePols[i][j].begin(), bluePols[i][j].end());
144
// Need to reverse orientation
145
for(i = 0; i < redPols.size(); ++i)
147
if(TeOrientation(redPols[i][0]) == TeCOUNTERCLOCKWISE)
148
reverse(redPols[i][0].begin(), redPols[i][0].end());
150
for(unsigned int j = 1; j < redPols[i].size(); ++j)
152
if(TeOrientation(redPols[i][j]) == TeCLOCKWISE)
153
reverse(redPols[i][j].begin(), redPols[i][j].end());
157
locationRedFragments = TeINSIDE;
158
locationBlueFragments = TeINSIDE;
162
// Union gets all fragments from red polygon wich are
163
// outside the blue polygon and the blue fragments that are outside
165
case TeUNION: if(TeDisjoint(redPols.box(), bluePols.box()))
169
for(i = 0; i < bluePols.size(); ++i)
170
result.add(bluePols[i]);
175
// Need to reverse orientation
176
for(i = 0; i < bluePols.size(); ++i)
178
if(TeOrientation(bluePols[i][0]) == TeCOUNTERCLOCKWISE)
179
reverse(bluePols[i][0].begin(), bluePols[i][0].end());
181
for(unsigned int j = 1; j < bluePols[i].size(); ++j)
183
if(TeOrientation(bluePols[i][j]) == TeCLOCKWISE)
184
reverse(bluePols[i][j].begin(), bluePols[i][j].end());
188
// Need to reverse orientation
189
for(i = 0; i < redPols.size(); ++i)
191
if(TeOrientation(redPols[i][0]) == TeCOUNTERCLOCKWISE)
192
reverse(redPols[i][0].begin(), redPols[i][0].end());
194
for(unsigned int j = 1; j < redPols[i].size(); ++j)
196
if(TeOrientation(redPols[i][j]) == TeCLOCKWISE)
197
reverse(redPols[i][j].begin(), redPols[i][j].end());
201
locationRedFragments = TeOUTSIDE;
202
locationBlueFragments = TeOUTSIDE;
206
// Difference gets all fragments from red polygon wich are
207
// outside the blue polygon and the blue fragments that are inside
209
case TeDIFFERENCE: if(TeDisjoint(redPols.box(), bluePols.box()))
212
locationRedFragments = TeOUTSIDE;
213
locationBlueFragments = TeINSIDE;
215
// Need to reverse orientation
216
for(i = 0; i < bluePols.size(); ++i)
218
if(TeOrientation(bluePols[i][0]) == TeCLOCKWISE)
219
reverse(bluePols[i][0].begin(), bluePols[i][0].end());
221
for(unsigned int j = 1; j < bluePols[i].size(); ++j)
223
if(TeOrientation(bluePols[i][j]) == TeCOUNTERCLOCKWISE)
224
reverse(bluePols[i][j].begin(), bluePols[i][j].end());
228
// Need to reverse orientation
229
for(i = 0; i < redPols.size(); ++i)
231
if(TeOrientation(redPols[i][0]) == TeCOUNTERCLOCKWISE)
232
reverse(redPols[i][0].begin(), redPols[i][0].end());
234
for(unsigned int j = 1; j < redPols[i].size(); ++j)
236
if(TeOrientation(redPols[i][j]) == TeCLOCKWISE)
237
reverse(redPols[i][j].begin(), redPols[i][j].end());
247
TeMultiGeometry TeChooseOperation(const short& operation, TeLineSet& redLines, TePolygonSet& bluePols, short& locationRedFragments)
249
TeMultiGeometry result;
253
// Intersection gets all fragments from red polygon wich are
254
// inside the blue polygon and the blue fragments that are inside
256
case TeINTERSECTION: if(TeDisjoint(redLines.box(), bluePols.box()))
259
locationRedFragments = TeINSIDE;
262
// Union gets all fragments from red polygon wich are
263
// outside the blue polygon and the blue fragments that are outside
265
case TeUNION: if(TeDisjoint(redLines.box(), bluePols.box()))
267
result.setGeometry(redLines);
268
result.setGeometry(bluePols);
273
locationRedFragments = TeOUTSIDE;
277
// Difference gets all fragments from red polygon wich are
278
// outside the blue polygon and the blue fragments that are inside
280
case TeDIFFERENCE: if(TeDisjoint(redLines.box(), bluePols.box()))
282
result.setGeometry(redLines);
286
locationRedFragments = TeOUTSIDE;
294
void TeRemoveOpositeBoundaryFragments(TeLineIndex& redFragmentsIndex, TeLineIndex& blueFragmentsIndex)
296
TeLineIndex::iterator indexIterator = blueFragmentsIndex.begin();
298
while(indexIterator != blueFragmentsIndex.end())
300
TeLineIndex::iterator idx = redFragmentsIndex.find(indexIterator->second.second[(indexIterator->second.second.size() - 1u)]);
302
if(idx != redFragmentsIndex.end())
304
if(TeEquals(idx->second.second[idx->second.second.size() - 1u], indexIterator->second.second[0u]))
306
redFragmentsIndex.erase(idx);
308
TeLineIndex::iterator idxAux;
309
idxAux = indexIterator;
311
blueFragmentsIndex.erase(idxAux);
323
void TeRemoveSameBoundaryFragments(TeLineIndex& redFragmentsIndex, TeLineIndex& blueFragmentsIndex)
325
TeLineIndex::iterator indexIterator = blueFragmentsIndex.begin();
327
while(indexIterator != blueFragmentsIndex.end())
329
TeLineIndex::iterator idx = redFragmentsIndex.find(indexIterator->second.second[0u]);
331
if(idx != redFragmentsIndex.end())
333
if(TeEquals(idx->second.second[idx->second.second.size() - 1u], indexIterator->second.second[(indexIterator->second.second.size() - 1u)]))
335
redFragmentsIndex.erase(idx);
345
void TeMergeFragments(TeLineIndex& fragmentsIndex, TeLineIndex& boundaryFragmentsIndex)
347
TeLineIndex::iterator indexIterator = boundaryFragmentsIndex.begin();
349
while(indexIterator != boundaryFragmentsIndex.end())
351
fragmentsIndex.insert(*indexIterator);
355
boundaryFragmentsIndex.clear();
358
void TeFindAndMoveClosedRings(TeLineIndex& fragmentsIndex, vector<TeLinearRing>& rings)
360
TeLineIndex::iterator indexIterator = fragmentsIndex.begin();
362
while(indexIterator != fragmentsIndex.end())
364
if(indexIterator->second.second.isRing())
366
rings.push_back(indexIterator->second.second);
368
TeLineIndex::iterator idxAux;
369
idxAux = indexIterator;
371
fragmentsIndex.erase(idxAux);
378
// Recebe um polygonset com an�is externos e um vetor de pol�gonos que seriam buracos e
379
// define em qual pol�gono colocar os buracos
380
bool TeMountTopology(TePolygonSet& polysOut, vector<TeLinearRing>& holes)
382
bool returnValue = true;
384
if((polysOut.size() == 0) && (holes.size() > 0))
386
return false; // Formou buracos e n�o formou os an�is externos
389
if(polysOut.size() == 1)
391
for(unsigned int i = 0; i < holes.size(); ++i)
392
polysOut[0].add(holes[i]);
396
for(unsigned int i = 0; i < holes.size(); ++i)
398
TeLinearRing ring = holes[i];
400
vector<TePolygon> candidates;
401
vector<unsigned int> candidatesPos;
405
for(j = 0; j < polysOut.size(); ++j)
407
if(TeWithinOrCoveredByOrEquals(ring.box(), polysOut[j].box()))
409
candidates.push_back(polysOut[j]);
410
candidatesPos.push_back(j);
414
if(candidates.size() == 1)
416
candidates[0].add(ring);
420
vector<TePolygon> newCandidates;
422
for(j = 0; j < candidates.size(); ++j)
424
short rel = TeBOUNDARY;
426
unsigned int nthVert = ring.size();
427
unsigned int iVert = 0u;
429
while(iVert < nthVert)
431
rel = TeRelation(ring[iVert], candidates[j][0]);
435
newCandidates.push_back(candidates[j]);
438
else if(rel & TeOUTSIDE)
448
// Erro topol�gico, todos os pontos est�o na fronteira do anel externo...
454
short whatRel = TeRelation(topTest, candidates[j]);
456
// Se um buraco for igual ao exterior, existe um erro topol�gico
457
// No momento, eliminamos o anel externo
459
// Se o buraco for coberto pelo pol�gono externo, ent�o ele ir� ficar dentro deste
460
// Caso contr�rio � erro sem possibilidades...
461
if(whatRel & TeEQUALS)
463
polysOut.erase(candidatesPos[j]);
469
if(newCandidates.size() <= 0)
471
// N�o encontrou o anel externo ao qual o buraco pertence
478
double minArea = TeMAXFLOAT;
480
for(j = 0; j < newCandidates.size(); ++j)
482
if(TeGeometryArea(newCandidates[j].box()) < minArea)
485
minArea = TeGeometryArea(newCandidates[j].box());
489
newCandidates[idxMinArea].add(ring);
496
// Set operation for rings
497
bool TeOVERLAY::TeOverlay(const TePolygonSet& redPolsIn, const TePolygonSet& bluePolsIn, TePolygonSet& polsOut, const short& operation)
501
short locationRedFragments = 0; // Wich red fragments to consider.
502
short locationBlueFragments = 0; // Wich blue fragments to consider.
504
short redMask = TeUNKNOWNPOSITION;
505
short blueMask = TeUNKNOWNPOSITION;
506
short location = TeUNKNOWNPOSITION;
508
TePolygonSet redPols;
509
TePolygonSet bluePols;
511
// Copia o conte�do dos pol�gonos de entrada
512
TeClonePolygonSet(redPolsIn, redPols);
513
TeClonePolygonSet(bluePolsIn, bluePols);
515
// Ajeita a orienta��o das fronteiras dos pol�gonos e determina a localiza��o dos fragmentos que ser�o utilizados
516
polsOut = TeChooseOperation(operation, redPols, bluePols, locationRedFragments, locationBlueFragments);
518
if(polsOut.size() > 0)
522
// If we are here so the rings are not disjoint by box
524
// Gets intersection list
525
TeINTERSECTOR2::TeVectorBoundaryIP report;
527
TeINTERSECTOR2::TeSafeIntersections(redPols, bluePols, report);
529
// So we need to create the fragments
530
TeLineIndex redFragmentsIndex;
531
TeLineIndex blueFragmentsIndex;
533
TeLineIndex redBoundaryFragmentsIndex;
534
TeLineIndex blueBoundaryFragmentsIndex;
538
for(unsigned int i = 0; i < redPols.size(); ++i)
539
for(unsigned int j = 0; j < redPols[i].size(); ++j)
540
redRings.add(redPols[i][j]);
543
for(unsigned int k = 0; k < bluePols.size(); ++k)
544
for(unsigned int j = 0; j < bluePols[k].size(); ++j)
545
blueRings.add(bluePols[k][j]);
547
// Choose red fragments
548
TeLineSet redFragments;
549
TeLineSet redFragmentsBoundary;
550
TeFragmentBoundary(redRings, report, redFragmentsBoundary, redFragments);
552
unsigned int setSize = redFragments.size();
556
if(redFragmentsBoundary.size())
557
redMask = TeBOUNDARY;
561
for(w = 0; w < redFragmentsBoundary.size(); ++w)
562
redBoundaryFragmentsIndex.insert(TeLineIndex::value_type(redFragmentsBoundary[w][0], pair<short, TeLine2D>(TeBOUNDARY, redFragmentsBoundary[w])));
564
vector<TeLinearRing> rings;
566
// Do a position test for each fragment and stop if all relations have been found.
567
for(w = 0; w < setSize; ++w)
569
if(redFragments[w].size() == 2) // If the fragment has two points I need to check the middle point of this fragment.
570
TeGetMiddlePoint(redFragments[w][0], redFragments[w][1], middle);
571
else // If the fragment has more than two points so I check one point between the end points.
572
middle = redFragments[w][(unsigned int)((double(redFragments[w].size()) / 2.0 + 0.6)) - 1];
574
location = TeRelation(middle, bluePols);
576
// If fragment is on location type or is boundary, get it.
577
if((location & locationRedFragments))
579
if(redFragments[w].isRing())
580
rings.push_back(redFragments[w]);
582
redFragmentsIndex.insert(TeLineIndex::value_type(redFragments[w][0], pair<short, TeLine2D>(w, redFragments[w])));
588
// Choose blue fragments
590
TeINTERSECTOR2::TeVectorBoundaryIP::iterator it = report.begin();
591
TeINTERSECTOR2::TeVectorBoundaryIP::iterator it_end = report.end();
595
swap(it->bluePartNum_, it->redPartNum_);
596
swap(it->blueSegNum_, it->redSegNum_);
600
// Choose blue fragments
601
TeLineSet blueFragments;
602
TeLineSet blueFragmentsBoundary;
604
TeFragmentBoundary(blueRings, report, blueFragmentsBoundary, blueFragments);
607
setSize = blueFragments.size();
609
for(w = 0; w < blueFragmentsBoundary.size(); ++w)
610
blueBoundaryFragmentsIndex.insert(TeLineIndex::value_type(blueFragmentsBoundary[w][0], pair<short, TeLine2D>(TeBOUNDARY, blueFragmentsBoundary[w])));
612
if(blueFragmentsBoundary.size())
613
blueMask = TeBOUNDARY;
615
// Do a position test for each fragment and stop if all relations have been found.
616
for(unsigned int j = 0; j < setSize; ++j)
618
if(blueFragments[j].size() == 2) // If the fragment has two points I need to check the middle point of this fragment.
619
TeGetMiddlePoint(blueFragments[j][0], blueFragments[j][1], middle);
620
else // If the fragment has more than two points so I check one point between the end points.
621
middle = blueFragments[j][(unsigned int)((double(blueFragments[j].size()) / 2.0 + 0.6)) - 1];
623
location = TeRelation(middle, redPols);
625
// If fragment is on location type or is boundary, get it.
626
if((location & locationBlueFragments))
628
if(blueFragments[j].isRing())
629
rings.push_back(blueFragments[j]);
631
blueFragmentsIndex.insert(TeLineIndex::value_type(blueFragments[j][0], pair<short, TeLine2D>(w, blueFragments[j])));
634
blueMask |= location;
637
// Remove closed rings => Only needs to test open segments
638
TeFindAndMoveClosedRings(redBoundaryFragmentsIndex, rings);
639
TeFindAndMoveClosedRings(blueBoundaryFragmentsIndex, rings);
642
// Try to eliminate oposite boundaries
643
TeRemoveOpositeBoundaryFragments(redBoundaryFragmentsIndex, blueBoundaryFragmentsIndex);
645
// Try to eliminate same boundary fragments
646
TeRemoveSameBoundaryFragments(redBoundaryFragmentsIndex, blueBoundaryFragmentsIndex);
648
// Merge all red fragments in the first fragment index
649
TeMergeFragments(redFragmentsIndex, redBoundaryFragmentsIndex);
651
// Merge all blue fragments in the first fragment index
652
TeMergeFragments(blueFragmentsIndex, blueBoundaryFragmentsIndex);
655
// Make polygons from fragments.
656
bool returnValue = true;
659
TeCoord2D endLineCoordinate;
661
while(!(redFragmentsIndex.empty() && blueFragmentsIndex.empty()))
665
TeLineIndex::iterator indexIterator = redFragmentsIndex.begin();
666
if(indexIterator != redFragmentsIndex.end())
668
if(indexIterator->second.second.isRing())
670
rings.push_back(indexIterator->second.second);
671
redFragmentsIndex.erase(indexIterator);
675
for(unsigned int i = 0; i < indexIterator->second.second.size(); ++i)
676
lAux.add(indexIterator->second.second[i]);
678
lAux.setBox(::TeUnion(lAux.box(), indexIterator->second.second.box()));
680
redFragmentsIndex.erase(indexIterator);
684
TeLineIndex::iterator indexIterator = blueFragmentsIndex.begin();
685
if(indexIterator != blueFragmentsIndex.end())
687
if(indexIterator->second.second.isRing())
689
rings.push_back(indexIterator->second.second);
690
blueFragmentsIndex.erase(indexIterator);
694
for(unsigned int i = 0; i < indexIterator->second.second.size(); ++i)
695
lAux.add(indexIterator->second.second[i]);
697
//lAux.copyElements(indexIterator->second);
698
lAux.setBox(::TeUnion(lAux.box(), indexIterator->second.second.box()));
699
blueFragmentsIndex.erase(indexIterator);
703
returnValue = false; //N�o poderia vir aqui, deveria ter sa�do no teste do la�o!!
709
endLineCoordinate = lAux[lAux.size() - 1];
711
// Try to find the beginning of the next fragment that is part of the polygon in the same list
712
TeLineIndex::iterator indexIterator = redFragmentsIndex.find(endLineCoordinate);
714
if(indexIterator != redFragmentsIndex.end())
716
for(unsigned int i = 1; i < indexIterator->second.second.size(); ++i)
717
lAux.add(indexIterator->second.second[i]);
719
lAux.setBox(::TeUnion(lAux.box(), indexIterator->second.second.box()));
720
redFragmentsIndex.erase(indexIterator);
724
indexIterator = blueFragmentsIndex.find(endLineCoordinate);
726
if(indexIterator != blueFragmentsIndex.end())
728
for(unsigned int i = 1; i < indexIterator->second.second.size(); ++i)
729
lAux.add(indexIterator->second.second[i]);
731
lAux.setBox(::TeUnion(lAux.box(), indexIterator->second.second.box()));
732
blueFragmentsIndex.erase(indexIterator);
739
rings.push_back(TeLinearRing(lAux));
742
returnValue = false; // Erro na topologia dos pol�gonos
754
rings.push_back(TeLinearRing(lAux));
763
returnValue = false; // Erro, alguma linha n�o fechou!!!
765
// Separate holes from islands
766
vector<TeLinearRing> holes;
769
for(unsigned int z = 0; z < rings.size(); ++z)
771
short ori = TeOrientation(rings[z]);
773
if(ori == TeCOUNTERCLOCKWISE) // It is a hole
775
holes.push_back(rings[z]); // add to holes list
777
else if(ori == TeCLOCKWISE) // else if island
778
{ // create a polygon
785
returnValue = false; // Objeto sem �rea? Isso � um erro!
789
if((polsOut.size() == 0) && (holes.size() == 0))
791
if(operation & TeUNION)
792
return false; // Na uni�o deve haver a forma��o de pol�gonos
794
return returnValue; // Diferen�a e interse��o podem retornar vazio
797
bool mountResult = TeMountTopology(polsOut, holes);
799
return (returnValue && mountResult);
802
TeMultiGeometry TeOVERLAY::TeOverlay(const TeLineSet& redLinesIn, const TePolygonSet& bluePolsIn, const short& operation)
804
short location = TeUNKNOWNPOSITION;
805
short locationRedFragments = TeUNKNOWNPOSITION;
807
TeMultiGeometry mGeom;
810
TePolygonSet bluePols;
813
// Copia o conte�do das linhas de entrada
814
TeCloneLineSet(redLinesIn, redLines);
816
// Copia o conte�do dos pol�gonos de entrada
817
TeClonePolygonSet(bluePolsIn, bluePols);
820
// Ajeita a orienta��o das fronteiras dos pol�gonos e determina a localiza��o dos fragmentos que ser�o utilizados
821
mGeom = TeChooseOperation(operation, redLines, bluePols, locationRedFragments);
828
// Gets intersection list
829
TeINTERSECTOR2::TeVectorBoundaryIP report;
831
unsigned int redLinesSize = redLines.size();
833
// Loops through red lines
834
for(i = 0u; i < redLinesSize; ++i)
836
unsigned int bluePart = 0u;
838
// Loops through blue polygonset
839
unsigned int bluePolsSize = bluePols.size();
841
for(unsigned int j = 0u; j < bluePolsSize; ++j)
843
//Loops trough blue polygon rings
844
unsigned int bluePolNumRings = bluePols[j].size();
846
for(unsigned k = 0u; k < bluePolNumRings; ++k)
848
TeINTERSECTOR2::TeSafeIntersections(redLines[i], bluePols[j][k], report, i, bluePart);
857
// Fragment red Lines
858
TeLineSet redFragments;
859
TeLineSet redFragmentsBoundary;
860
TeFragmentBoundary(redLines, report, redFragmentsBoundary, redFragments);
862
// Choose red fragments
863
unsigned int setSize = redFragments.size();
867
for(i = 0u; i < setSize; ++i)
869
if(redFragments[i].size() == 2) // If the fragment has two points I need to check the middle point of this fragment.
870
TeGetMiddlePoint(redFragments[i][0u], redFragments[i][1u], middle);
871
else // If the fragment has more than two points so I check one point between the end points.
872
middle = redFragments[i][(unsigned int)((double(redFragments[i].size()) / 2.0 + 0.6)) - 1];
874
location = TeRelation(middle, bluePols);
876
// If fragment is on location type, get it.
877
if((location & locationRedFragments))
878
mGeom.addGeometry(redFragments[i]);
883
case TeINTERSECTION: break;
885
case TeUNION: mGeom.setGeometry(bluePols);
888
case TeDIFFERENCE: break;