1 
2 
3 //#include "tsystem.h"
4 #include "tmachine.h"
5 #include "tcurves.h"
6 #include "tcommon.h"
7 #include "tregion.h"
8 //#include "tregionutil.h"
9 #include "tstopwatch.h"
10 
11 #include "tstroke.h"
12 #include "tstrokeutil.h"
13 #include "tvectorimageP.h"
14 #include "tdebugmessage.h"
15 #include "tthreadmessage.h"
16 #include "tl2lautocloser.h"
17 #include "tcomputeregions.h"
18 #include <vector>
19 
20 #include "tcurveutil.h"
21 
22 #include <algorithm>
23 
24 #if !defined(TNZ_LITTLE_ENDIAN)
25 TNZ_LITTLE_ENDIAN undefined !!
26 #endif
27 
28 //-----------------------------------------------------------------------------
29 
30 #ifdef IS_DOTNET
31 #define NULL_ITER list<IntersectedStroke>::iterator()
32 #else
33 #define NULL_ITER 0
34 #endif
35 
36     using namespace std;
37 
38 typedef TVectorImage::IntersectionBranch IntersectionBranch;
39 //-----------------------------------------------------------------------------
40 
myRound(double x)41 inline double myRound(double x) {
42   return (1.0 / REGION_COMPUTING_PRECISION) *
43          ((TINT32)(x * REGION_COMPUTING_PRECISION));
44 }
45 
myRound(const TThickPoint & p)46 inline TThickPoint myRound(const TThickPoint &p) {
47   return TThickPoint(myRound(p.x), myRound(p.y), p.thick);
48 }
49 
roundStroke(TStroke * s)50 static void roundStroke(TStroke *s) {
51   int size = s->getControlPointCount();
52 
53   for (int j = 0; j < (int)s->getControlPointCount(); j++) {
54     TThickPoint p = s->getControlPoint(j);
55     s->setControlPoint(j, myRound(p));
56   }
57   if (size > 3)
58   //! it can happen that a stroke has a first or last quadratic degenerated:(3
59   //! equal control points).
60   // in that case, if the stroke has an intersection in an endpoint, the
61   // resulting w could not be  0 or 1 as expected.
62   // since the w==0 and w==1 are used in the region computing to determine if
63   // the intersection is an endpoint,
64   //
65 
66   {
67     if (s->getControlPoint(0) == s->getControlPoint(1) &&
68         s->getControlPoint(0) == s->getControlPoint(2)) {
69       s->setControlPoint(2, s->getControlPoint(3));
70       s->setControlPoint(1, s->getControlPoint(3));
71     }
72     if (s->getControlPoint(size - 1) == s->getControlPoint(size - 2) &&
73         s->getControlPoint(size - 1) == s->getControlPoint(size - 3)) {
74       s->setControlPoint(size - 2, s->getControlPoint(size - 4));
75       s->setControlPoint(size - 3, s->getControlPoint(size - 4));
76     }
77   }
78 }
79 
80 //-----------------------------------------------------------------------------
81 class VIListElem {
82 public:
83   VIListElem *m_prev;
84   VIListElem *m_next;
85 
VIListElem()86   VIListElem() : m_prev(0), m_next(0) {}
next()87   inline VIListElem *next() { return m_next; }
prev()88   inline VIListElem *prev() { return m_prev; }
89 };
90 
91 template <class T>
92 class VIList {
93   int m_size;
94   T *m_begin, *m_end;
95 
96 public:
VIList()97   VIList() : m_begin(0), m_end(0), m_size(0) {}
98 
first() const99   inline T *first() const { return m_begin; };
last() const100   inline T *last() const { return m_end; };
101 
102   void clear();
103   void pushBack(T *elem);
104   void insert(T *before, T *elem);
105   T *erase(T *element);
106   T *getElemAt(int pos);
107   int getPosOf(T *elem);
size()108   inline int size() { return m_size; }
empty()109   inline bool empty() { return size() == 0; }
110 };
111 
112 class Intersection final : public VIListElem {
113 public:
114   // Intersection* m_prev, *m_next;
115   TPointD m_intersection;
116   int m_numInter;
117   // bool m_isNotErasable;
118   VIList<IntersectedStroke> m_strokeList;
119 
Intersection()120   Intersection() : m_numInter(0), m_strokeList() {}
121 
next()122   inline Intersection *next() { return (Intersection *)VIListElem::next(); };
prev()123   inline Intersection *prev() { return (Intersection *)VIListElem::prev(); };
124   // inline Intersection* operator++() {return next();}
125 };
126 
127 class IntersectedStrokeEdges {
128 public:
129   int m_index;
130   list<TEdge *> m_edgeList;
IntersectedStrokeEdges(int index)131   IntersectedStrokeEdges(int index) : m_index(index), m_edgeList() {}
~IntersectedStrokeEdges()132   ~IntersectedStrokeEdges() {
133     assert(m_index >= 0); /*clearPointerContainer(m_edgeList);*/
134     m_edgeList.clear();
135     m_index = -1;
136   }
137 };
138 
139 class IntersectionData {
140 public:
141   UINT maxAutocloseId;
142   VIList<Intersection> m_intList;
143   map<int, VIStroke *> m_autocloseMap;
144   vector<IntersectedStrokeEdges> m_intersectedStrokeArray;
145 
IntersectionData()146   IntersectionData() : maxAutocloseId(1), m_intList() {}
147 
148   ~IntersectionData();
149 };
150 
151 //-----------------------------------------------------------------------------
152 
153 class IntersectedStroke final : public VIListElem {
154   /*double m_w;
155 TStroke *m_s;
156 UINT m_index;*/
157   // IntersectedStroke* m_prev, *m_next;
158 public:
159   TEdge m_edge;
160   Intersection *m_nextIntersection;
161   IntersectedStroke *m_nextStroke;
162   bool m_visited, m_gettingOut;  //, m_dead;
163 
IntersectedStroke()164   IntersectedStroke()
165       : m_visited(false), m_nextIntersection(0), m_nextStroke(0){};
166 
IntersectedStroke(Intersection * nextIntersection,IntersectedStroke * nextStroke)167   IntersectedStroke(Intersection *nextIntersection,
168                     IntersectedStroke *nextStroke)
169       /*: m_w(-1.0)
170 , m_s(NULL)
171 , m_index(0)*/
172       : m_edge(),
173         m_nextIntersection(nextIntersection),
174         m_nextStroke(nextStroke),
175         m_visited(false)
176   //, m_dead(false)
177   {}
178 
IntersectedStroke(const IntersectedStroke & s)179   IntersectedStroke(const IntersectedStroke &s)
180       : m_edge(s.m_edge, false)
181       , m_nextIntersection(s.m_nextIntersection)
182       , m_nextStroke(s.m_nextStroke)
183       , m_visited(s.m_visited)
184       , m_gettingOut(s.m_gettingOut)
185   //, m_dead(s.m_dead)
186   {}
187 
next()188   inline IntersectedStroke *next() {
189     return (IntersectedStroke *)VIListElem::next();
190   };
191 };
192 
193 //=============================================================================
194 
195 template <class T>
clear()196 void VIList<T>::clear() {
197   while (m_begin) {
198     T *aux  = m_begin;
199     m_begin = m_begin->next();
200     delete aux;
201   }
202   m_end  = 0;
203   m_size = 0;
204 }
205 
206 template <class T>
pushBack(T * elem)207 void VIList<T>::pushBack(T *elem) {
208   if (!m_begin) {
209     assert(!m_end);
210     elem->m_next = elem->m_prev = 0;
211     m_begin = m_end = elem;
212   } else {
213     assert(m_end);
214     assert(m_end->m_next == 0);
215     m_end->m_next = elem;
216     elem->m_prev  = m_end;
217     elem->m_next  = 0;
218     m_end         = elem;
219   }
220   m_size++;
221 }
222 
223 template <class T>
insert(T * before,T * elem)224 void VIList<T>::insert(T *before, T *elem) {
225   assert(before && elem);
226 
227   elem->m_prev = before->m_prev;
228   elem->m_next = before;
229 
230   if (!before->m_prev)
231     before->m_prev = m_begin = elem;
232   else {
233     before->m_prev->m_next = elem;
234     before->m_prev         = elem;
235   }
236   m_size++;
237 }
238 
239 template <class T>
erase(T * element)240 T *VIList<T>::erase(T *element) {
241   T *ret;
242 
243   assert(m_size > 0);
244   if (!element->m_prev) {
245     assert(m_begin == element);
246     if (!element->m_next)
247       ret = m_begin = m_end = 0;
248     else {
249       m_begin         = (T *)m_begin->m_next;
250       m_begin->m_prev = 0;
251       ret             = m_begin;
252     }
253   } else if (!element->m_next) {
254     assert(m_end == element);
255     m_end         = (T *)m_end->m_prev;
256     m_end->m_next = 0;
257     ret           = 0;
258   } else {
259     element->m_prev->m_next = element->m_next;
260     element->m_next->m_prev = element->m_prev;
261     ret                     = (T *)element->m_next;
262   }
263   m_size--;
264   delete element;
265   return ret;
266 }
267 
268 template <class T>
getElemAt(int pos)269 T *VIList<T>::getElemAt(int pos) {
270   assert(pos < m_size);
271   T *p            = m_begin;
272   while (pos--) p = p->next();
273   return p;
274 }
275 
276 template <class T>
getPosOf(T * elem)277 int VIList<T>::getPosOf(T *elem) {
278   int count = 0;
279   T *p      = m_begin;
280 
281   while (p && p != elem) {
282     count++;
283     p = p->next();
284   }
285   assert(p == elem);
286   return count;
287 }
288 
289 //-------------------------------------------------------------
290 
291 //-----------------------------------------------------------------------------
292 
293 #ifdef LEVO
294 
print(list<Intersection> & intersectionList,char * str)295 void print(list<Intersection> &intersectionList, char *str) {
296   ofstream of(str);
297 
298   of << "***************************" << endl;
299 
300   list<Intersection>::const_iterator it;
301   list<IntersectedStroke>::const_iterator it1;
302   int i, j;
303   for (i = 0, it = intersectionList.begin(); it != intersectionList.end();
304        it++, i++) {
305     of << "***************************" << endl;
306     of << "Intersection#" << i << ": " << it->m_intersection
307        << "numBranches: " << it->m_numInter << endl;
308     of << endl;
309 
310     for (j = 0, it1 = it->m_strokeList.begin(); it1 != it->m_strokeList.end();
311          it1++, j++) {
312       of << "----Branch #" << j;
313       if (it1->m_edge.m_index < 0) of << "(AUTOCLOSE)";
314       of << "Intersection at " << it1->m_edge.m_w0 << ": "
315          << ": " << endl;
316       of << "ColorId: " << it1->m_edge.m_styleId << endl;
317       /*
318 TColorStyle* fs = it1->m_edge.m_fillStyle;
319 if (fs==0)
320 of<<"NO color: "<< endl;
321 else
322 {
323 TFillStyleP fp = fs->getFillStyle();
324 if (fp)
325 {
326 fp->
327 assert(false) ;
328 else
329 of<<"Color: ("<< colorStyle->getColor().r<<", "<< colorStyle->getColor().g<<",
330 "<< colorStyle->getColor().b<<")"<<endl;
331 */
332 
333       of << "----Stroke " << (it1->m_gettingOut ? "OUT" : "IN") << " #"
334          << it1->m_edge.m_index << ": " << endl;
335       // if (it1->m_dead)
336       // of<<"---- DEAD Intersection.";
337       // else
338       {
339         of << "---- NEXT Intersection:";
340         if (it1->m_nextIntersection != intersectionList.end()) {
341           int dist =
342               std::distance(intersectionList.begin(), it1->m_nextIntersection);
343           of << dist;
344           list<Intersection>::iterator iit = intersectionList.begin();
345           std::advance(iit, dist);
346           of << " "
347              << std::distance(iit->m_strokeList.begin(), it1->m_nextStroke);
348         }
349 
350         else
351           of << "NULL!!";
352         of << "---- NEXT Stroke:";
353         if (it1->m_nextIntersection != intersectionList.end())
354           of << it1->m_nextStroke->m_edge.m_index;
355         else
356           of << "NULL!!";
357       }
358       of << endl << endl;
359     }
360   }
361 }
362 
363 #endif
364 
365 void findNearestIntersection(list<Intersection> &interList,
366                              const list<Intersection>::iterator &i1,
367                              const list<IntersectedStroke>::iterator &i2);
368 
369 //-----------------------------------------------------------------------------
370 
371 #ifdef _TOLGO
checkInterList(list<Intersection> & intersectionList)372 void checkInterList(list<Intersection> &intersectionList) {
373   list<Intersection>::iterator it;
374   list<IntersectedStroke>::iterator it1;
375 
376   for (it = intersectionList.begin(); it != intersectionList.end(); it++) {
377     int count = 0;
378     for (it1 = it->m_strokeList.begin(); it1 != it->m_strokeList.end(); it1++) {
379       int val;
380       if (it1->m_nextIntersection != intersectionList.end()) {
381         count++;
382         // assert (it1->m_nextIntersection!=intersectionList.end());
383         assert(it1->m_nextStroke->m_nextIntersection == it);
384         assert(it1->m_nextStroke->m_nextStroke == it1);
385 
386         // int k = it1->m_edge.m_index;
387         val = std::distance(intersectionList.begin(), it1->m_nextIntersection);
388       }
389       // else
390       // assert(it1->m_nextIntersection==intersectionList.end());
391     }
392     assert(count == it->m_numInter);
393   }
394 }
395 #else
396 #define checkInterList
397 #endif
398 
399 //-----------------------------------------------------------------------------
400 
401 // void addFakeIntersection(list<Intersection>& intersectionList,TStroke* s,
402 // UINT ii, double w);
403 
404 void addIntersections(IntersectionData &intersectionData,
405                       const vector<VIStroke *> &s, int ii, int jj,
406                       const vector<DoublePair> &intersections, int numStrokes,
407                       bool isVectorized);
408 
409 void addIntersection(IntersectionData &intData, const vector<VIStroke *> &s,
410                      int ii, int jj, DoublePair intersections, int strokeSize,
411                      bool isVectorized);
412 
413 //-----------------------------------------------------------------------------
414 
sortBBox(const TStroke * s1,const TStroke * s2)415 static bool sortBBox(const TStroke *s1, const TStroke *s2) {
416   return s1->getBBox().x0 < s2->getBBox().x0;
417 }
418 
419 //-----------------------------------------------------------------------------
420 
cleanIntersectionMarks(const VIList<Intersection> & interList)421 static void cleanIntersectionMarks(const VIList<Intersection> &interList) {
422   Intersection *p;
423   IntersectedStroke *q;
424   for (p = interList.first(); p; p = p->next())
425     for (q = p->m_strokeList.first(); q; q = q->next()) {
426       q->m_visited =
427           false;  // Ogni ramo della lista viene messo nella condizione
428                   // di poter essere visitato
429 
430       if (q->m_nextIntersection) {
431         q->m_nextIntersection = 0;
432         p->m_numInter--;
433       }
434     }
435 }
436 
437 //-----------------------------------------------------------------------------
438 
cleanNextIntersection(const VIList<Intersection> & interList,TStroke * s)439 static void cleanNextIntersection(const VIList<Intersection> &interList,
440                                   TStroke *s) {
441   Intersection *p;
442   IntersectedStroke *q;
443 
444   for (p = interList.first(); p; p = p->next())
445     for (q = p->m_strokeList.first(); q; q = q->next())
446       if (q->m_edge.m_s == s) {
447         // if (it2->m_nextIntersection==NULL)
448         //  return; //gia' ripulita prima
449         if (q->m_nextIntersection) {
450           q->m_nextIntersection = 0;
451           p->m_numInter--;
452         }
453         q->m_nextStroke = 0;
454       }
455 }
456 
457 //-----------------------------------------------------------------------------
458 
eraseEdgeFromStroke(IntersectedStroke * is)459 void TVectorImage::Imp::eraseEdgeFromStroke(IntersectedStroke *is) {
460   if (is->m_edge.m_index >= 0 &&
461       is->m_edge.m_index < m_strokes.size())  // elimino il puntatore all'edge
462                                               // nella lista della VIStroke
463   {
464     VIStroke *s;
465     s = m_strokes[is->m_edge.m_index];
466     assert(s->m_s == is->m_edge.m_s);
467     list<TEdge *>::iterator iit  = s->m_edgeList.begin(),
468                             it_e = s->m_edgeList.end();
469 
470     for (; iit != it_e; ++iit)
471       if ((*iit)->m_w0 == is->m_edge.m_w0 && (*iit)->m_w1 == is->m_edge.m_w1) {
472         assert((*iit)->m_toBeDeleted == false);
473         s->m_edgeList.erase(iit);
474         return;
475       }
476   }
477 }
478 
479 //-----------------------------------------------------------------------------
480 
eraseBranch(Intersection * in,IntersectedStroke * is)481 IntersectedStroke *TVectorImage::Imp::eraseBranch(Intersection *in,
482                                                   IntersectedStroke *is) {
483   if (is->m_nextIntersection) {
484     Intersection *nextInt         = is->m_nextIntersection;
485     IntersectedStroke *nextStroke = is->m_nextStroke;
486     assert(nextStroke->m_nextIntersection == in);
487     assert(nextStroke->m_nextStroke == is);
488     assert(nextStroke != is);
489 
490     // nextStroke->m_nextIntersection = intList.end();
491     // nextStroke->m_nextStroke = nextInt->m_strokeList.end();
492 
493     if (nextStroke->m_nextIntersection) {
494       nextStroke->m_nextIntersection = 0;
495       nextInt->m_numInter--;
496     }
497     // nextInt->m_strokeList.erase(nextStroke);//non posso cancellarla, puo'
498     // servire in futuro!
499   }
500   if (is->m_nextIntersection) in->m_numInter--;
501 
502   eraseEdgeFromStroke(is);
503 
504   is->m_edge.m_w0 = is->m_edge.m_w1 = -3;
505   is->m_edge.m_index                = -3;
506   is->m_edge.m_s                    = 0;
507   is->m_edge.m_styleId              = -3;
508 
509   return in->m_strokeList.erase(is);
510 }
511 
512 //-----------------------------------------------------------------------------
513 
eraseDeadIntersections()514 void TVectorImage::Imp::eraseDeadIntersections() {
515   Intersection *p = m_intersectionData->m_intList.first();
516 
517   while (p)  // la faccio qui, e non nella eraseIntersection. vedi commento li'.
518   {
519     // Intersection* &intList = m_intersectionData->m_intList;
520 
521     if (p->m_strokeList.size() == 1) {
522       eraseBranch(p, p->m_strokeList.first());
523       assert(p->m_strokeList.size() == 0);
524       p = m_intersectionData->m_intList.erase(p);
525     } else if (p->m_strokeList.size() == 2 &&
526                (p->m_strokeList.first()->m_edge.m_s ==
527                     p->m_strokeList.last()->m_edge.m_s &&
528                 p->m_strokeList.first()->m_edge.m_w0 ==
529                     p->m_strokeList.last()->m_edge.m_w0))  // intersezione finta
530     {
531       IntersectedStroke *it1 = p->m_strokeList.first(), *iit1, *iit2;
532       IntersectedStroke *it2 = it1->next();
533 
534       eraseEdgeFromStroke(p->m_strokeList.first());
535       eraseEdgeFromStroke(p->m_strokeList.first()->next());
536 
537       iit1 = (it1->m_nextIntersection) ? it1->m_nextStroke : 0;
538       iit2 = (it2->m_nextIntersection) ? it2->m_nextStroke : 0;
539 
540       if (iit1 && iit2) {
541         iit1->m_edge.m_w1 = iit2->m_edge.m_w0;
542         iit2->m_edge.m_w1 = iit1->m_edge.m_w0;
543       }
544       if (iit1) {
545         iit1->m_nextStroke       = iit2;
546         iit1->m_nextIntersection = it2->m_nextIntersection;
547         if (!iit1->m_nextIntersection) it1->m_nextIntersection->m_numInter--;
548       }
549 
550       if (iit2) {
551         iit2->m_nextStroke       = iit1;
552         iit2->m_nextIntersection = it1->m_nextIntersection;
553         if (!iit2->m_nextIntersection) it2->m_nextIntersection->m_numInter--;
554       }
555 
556       p->m_strokeList.clear();
557       p->m_numInter = 0;
558       p             = m_intersectionData->m_intList.erase(p);
559     } else
560       p = p->next();
561   }
562 }
563 
564 //-----------------------------------------------------------------------------
565 
doEraseIntersection(int index,vector<int> * toBeDeleted)566 void TVectorImage::Imp::doEraseIntersection(int index,
567                                             vector<int> *toBeDeleted) {
568   Intersection *p1  = m_intersectionData->m_intList.first();
569   TStroke *deleteIt = 0;
570 
571   while (p1) {
572     bool removeAutocloses = false;
573 
574     IntersectedStroke *p2 = p1->m_strokeList.first();
575 
576     while (p2) {
577       IntersectedStroke &is = *p2;
578 
579       if (is.m_edge.m_index == index) {
580         if (is.m_edge.m_index >= 0)
581           // if (!is.m_autoclose && (is.m_edge.m_w0==1 || is.m_edge.m_w0==0))
582           removeAutocloses = true;
583         else
584           deleteIt = is.m_edge.m_s;
585         p2         = eraseBranch(p1, p2);
586       } else
587         p2 = p2->next();
588       // checkInterList(interList);
589     }
590     if (removeAutocloses)  // se ho tolto una stroke dall'inter corrente, tolgo
591                            // tutti le stroke di autclose che partono da qui
592     {
593       assert(toBeDeleted);
594       for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next())
595         if (p2->m_edge.m_index < 0 &&
596             (p2->m_edge.m_w0 == 1 || p2->m_edge.m_w0 == 0))
597           toBeDeleted->push_back(p2->m_edge.m_index);
598     }
599 
600     if (p1->m_strokeList.empty())
601       p1 = m_intersectionData->m_intList.erase(p1);
602     else
603       p1 = p1->next();
604   }
605 
606   if (deleteIt) {
607 	  m_intersectionData->m_autocloseMap.erase(index);
608 	  delete deleteIt;
609   }
610 }
611 
612 //-----------------------------------------------------------------------------
613 
getFillData(std::unique_ptr<IntersectionBranch[]> & v)614 UINT TVectorImage::Imp::getFillData(std::unique_ptr<IntersectionBranch[]> &v) {
615   // print(m_intersectionData->m_intList,
616   // "C:\\temp\\intersectionPrimaSave.txt");
617 
618   // Intersection* intList = m_intersectionData->m_intList;
619   if (m_intersectionData->m_intList.empty()) return 0;
620 
621   Intersection *p1;
622   IntersectedStroke *p2;
623   UINT currInt = 0;
624   vector<UINT> branchesBefore(m_intersectionData->m_intList.size() + 1);
625 
626   branchesBefore[0] = 0;
627   UINT count = 0, size = 0;
628 
629   p1 = m_intersectionData->m_intList.first();
630 
631   for (; p1; p1 = p1->next(), currInt++) {
632     UINT strokeListSize = p1->m_strokeList.size();
633     size += strokeListSize;
634     branchesBefore[currInt + 1] = branchesBefore[currInt] + strokeListSize;
635   }
636 
637   v.reset(new IntersectionBranch[size]);
638   currInt = 0;
639   p1      = m_intersectionData->m_intList.first();
640   for (; p1; p1 = p1->next(), currInt++) {
641     UINT currBranch = 0;
642     for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next(), currBranch++) {
643       IntersectionBranch &b = v[count];
644       b.m_currInter         = currInt;
645       b.m_strokeIndex       = p2->m_edge.m_index;
646       b.m_w                 = p2->m_edge.m_w0;
647       b.m_style             = p2->m_edge.m_styleId;
648       // assert(b.m_style<100);
649       b.m_gettingOut = p2->m_gettingOut;
650       if (!p2->m_nextIntersection)
651         b.m_nextBranch = count;
652       else {
653         UINT distInt =
654             m_intersectionData->m_intList.getPosOf(p2->m_nextIntersection);
655         UINT distBranch =
656             p2->m_nextIntersection->m_strokeList.getPosOf(p2->m_nextStroke);
657 
658         if ((distInt < currInt) ||
659             (distInt == currInt && distBranch < currBranch)) {
660           UINT posNext = branchesBefore[distInt] + distBranch;
661           assert(posNext < count);
662           b.m_nextBranch = posNext;
663           assert(v[posNext].m_nextBranch == (std::numeric_limits<UINT>::max)());
664           v[posNext].m_nextBranch = count;
665         } else
666           b.m_nextBranch = (std::numeric_limits<UINT>::max)();
667       }
668       count++;
669     }
670   }
671 
672 // for (UINT i=0; i<count; i++)
673 //  assert(v[i].m_nextBranch != std::numeric_limits<UINT>::max());
674 
675 #ifdef _DEBUG
676 /*ofstream of("C:\\temp\\fillDataOut.txt");
677 
678 for (UINT ii=0; ii<size; ii++)
679   {
680   of<<ii<<"----------------------"<<endl;
681   of<<"index:"<<v[ii].m_strokeIndex<<endl;
682   of<<"w:"<<v[ii].m_w<<endl;
683   of<<"curr inter:"<<v[ii].m_currInter<<endl;
684   of<<"next inter:"<<v[ii].m_nextBranch<<endl;
685   of<<"gettingOut:"<<((v[ii].m_gettingOut)?"TRUE":"FALSE")<<endl;
686   of<<"colorId:"<<v[ii].m_style<<endl;
687   }*/
688 #endif
689 
690   return size;
691 }
692 
693 //-----------------------------------------------------------------------------
694 
695 //-----------------------------------------------------------------------------
696 namespace {
reconstructAutocloseStroke(Intersection * p1,IntersectedStroke * p2)697 TStroke *reconstructAutocloseStroke(Intersection *p1, IntersectedStroke *p2)
698 
699 {
700   bool found        = false;
701   Intersection *pp1 = p1->next();
702   IntersectedStroke *pp2;
703 
704   // vector<TEdge*> vapp;
705   for (; !found && pp1; pp1 = pp1->next()) {
706     for (pp2 = pp1->m_strokeList.first(); !found && pp2; pp2 = pp2->next()) {
707       if (p2->m_edge.m_index == pp2->m_edge.m_index) {
708         if ((pp2->m_edge.m_w0 == 1 && p2->m_edge.m_w0 == 0) ||
709             (pp2->m_edge.m_w0 == 0 && p2->m_edge.m_w0 == 1)) {
710           found = true;
711           vector<TPointD> v;
712           if (p2->m_edge.m_w0 == 0) {
713             v.push_back(p1->m_intersection);
714             v.push_back(pp1->m_intersection);
715           } else {
716             v.push_back(pp1->m_intersection);
717             v.push_back(p1->m_intersection);
718           }
719           p2->m_edge.m_s = pp2->m_edge.m_s = new TStroke(v);
720           // for (UINT ii=0; ii<vapp.size(); ii++)
721           // vapp[ii]->m_s = it2->m_edge.m_s;
722         }
723         // else if (iit2->m_edge.m_w0!=0 && iit2->m_edge.m_w0!=1)
724         //  vapp.push_back(&(iit2->m_edge));
725       }
726     }
727   }
728   assert(found);
729   if (!found) p2->m_edge.m_s = 0;
730 
731   return p2->m_edge.m_s;
732 }
733 
734 }  // namespace
735 //-----------------------------------------------------------------------------
736 
setFillData(std::unique_ptr<IntersectionBranch[]> const & v,UINT branchCount,bool doComputeRegions)737 void TVectorImage::Imp::setFillData(
738     std::unique_ptr<IntersectionBranch[]> const &v, UINT branchCount,
739     bool doComputeRegions) {
740 #ifdef _DEBUG
741 /*ofstream of("C:\\temp\\fillDataIn.txt");
742 
743 for (UINT ii=0; ii<branchCount; ii++)
744   {
745   of<<ii<<"----------------------"<<endl;
746   of<<"index:"<<v[ii].m_strokeIndex<<endl;
747   of<<"w:"<<v[ii].m_w<<endl;
748   of<<"curr inter:"<<v[ii].m_currInter<<endl;
749   of<<"next inter:"<<v[ii].m_nextBranch<<endl;
750   of<<"gettingOut:"<<((v[ii].m_gettingOut)?"TRUE":"FALSE")<<endl;
751   of<<"colorId:"<<v[ii].m_style<<endl;
752   }*/
753 #endif
754 
755   if (branchCount == 0) return;
756 
757   //{
758   // QMutexLocker sl(m_mutex);
759 
760   VIList<Intersection> &intList = m_intersectionData->m_intList;
761 
762   clearPointerContainer(m_regions);
763   m_regions.clear();
764   intList.clear();
765   Intersection *currInt;
766   IntersectedStroke *currBranch;
767 
768   UINT size = v[branchCount - 1].m_currInter + 1;
769   vector<UINT> branchesBefore(size);
770 
771   UINT i = 0;
772   for (; i < branchCount; i++) {
773     const IntersectionBranch &b = v[i];
774     if (i == 0 || v[i].m_currInter != v[i - 1].m_currInter) {
775       if (v[i].m_currInter >=
776           size)  // pezza per immagine corrotte...evito crash
777       {
778         break;
779       }
780 
781       branchesBefore[v[i].m_currInter] = i;
782 
783       currInt = new Intersection();
784       intList.pushBack(currInt);
785     }
786 
787     currBranch = new IntersectedStroke();
788     currInt->m_strokeList.pushBack(currBranch);
789 
790     currBranch->m_edge.m_styleId = b.m_style;
791     // assert(b.m_style<100);
792     currBranch->m_edge.m_index = b.m_strokeIndex;
793     if (b.m_strokeIndex >= 0 && b.m_strokeIndex < m_strokes.size())
794       currBranch->m_edge.m_s = m_strokes[b.m_strokeIndex]->m_s;
795     else
796       currBranch->m_edge.m_s = 0;
797     currBranch->m_gettingOut = b.m_gettingOut;
798     currBranch->m_edge.m_w0  = b.m_w;
799     if (b.m_nextBranch < branchCount)
800       currBranch->m_edge.m_w1 = v[b.m_nextBranch].m_w;
801     else
802       currBranch->m_edge.m_w1 = 1.0;
803     assert(currBranch->m_edge.m_w0 >= -1e-8 &&
804            currBranch->m_edge.m_w0 <= 1 + 1e-8);
805     assert(currBranch->m_edge.m_w1 >= -1e-8 &&
806            currBranch->m_edge.m_w1 <= 1 + 1e-8);
807 
808     if (b.m_nextBranch < i) {
809       Intersection *p1;
810       IntersectedStroke *p2;
811       p1 = intList.getElemAt(v[b.m_nextBranch].m_currInter);
812 
813       assert(b.m_nextBranch - branchesBefore[v[b.m_nextBranch].m_currInter] >=
814              0);
815       p2 = p1->m_strokeList.getElemAt(
816           b.m_nextBranch - branchesBefore[v[b.m_nextBranch].m_currInter]);
817 
818       currBranch->m_nextIntersection = p1;
819       currBranch->m_nextStroke       = p2;
820       p2->m_nextIntersection         = currInt;
821       p2->m_nextStroke               = currBranch;
822 
823       // if (currBranch == currInt->m_strokeList.begin())
824       //  currInt->m_intersection =
825       //  currBranch->m_edge.m_s->getPoint(currBranch->m_edge.m_w0);
826 
827       currInt->m_numInter++;
828       p1->m_numInter++;
829     } else if (b.m_nextBranch == i)
830       currBranch->m_nextIntersection = 0;
831     else if (b.m_nextBranch == (std::numeric_limits<UINT>::max)()) {
832       currBranch->m_nextIntersection = 0;
833       currBranch->m_nextStroke       = 0;
834     }
835 
836     /* {
837 assert(b.m_nextBranch<branchCount);
838 assert(v[b.m_nextBranch].m_nextBranch==i);
839 }*/
840 
841     if (i == branchCount - 1 || v[i].m_currInter != v[i + 1].m_currInter) {
842       int j = i;
843       while (v[j].m_strokeIndex < 0 &&
844              ((j > 0 && v[j].m_currInter == v[j - 1].m_currInter) || j == 0))
845         j--;
846       if (v[j].m_strokeIndex >= 0 && v[j].m_strokeIndex < m_strokes.size())
847         currInt->m_intersection =
848             m_strokes[v[j].m_strokeIndex]->m_s->getPoint(v[j].m_w);
849     }
850   }
851 
852   for (i = 0; i < m_strokes.size(); i++) m_strokes[i]->m_isNewForFill = false;
853 
854   // computeRegions();
855 
856   Intersection *p1;
857   IntersectedStroke *p2;
858 
859   vector<UINT> toBeDeleted;
860 
861   for (p1 = intList.first(); p1; p1 = p1->next())
862     for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next()) {
863       if (p2->m_edge.m_index < 0 && !p2->m_edge.m_s &&
864           (p2->m_edge.m_w0 == 0 || p2->m_edge.m_w0 == 1)) {
865         p2->m_edge.m_s = reconstructAutocloseStroke(p1, p2);
866         if (p2->m_edge.m_s)
867           m_intersectionData->m_autocloseMap[p2->m_edge.m_index] =
868               new VIStroke(p2->m_edge.m_s, TGroupId());
869         else
870           toBeDeleted.push_back(p2->m_edge.m_index);
871       }
872     }
873 
874   for (p1 = intList.first(); p1; p1 = p1->next())
875     for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next()) {
876       if (!p2->m_edge.m_s && p2->m_edge.m_index < 0) {
877         VIStroke *vs = m_intersectionData->m_autocloseMap[p2->m_edge.m_index];
878         if (vs) {
879 			p2->m_edge.m_s =
880               m_intersectionData->m_autocloseMap[p2->m_edge.m_index]->m_s;
881 
882           // TEdge& e = it2->m_edge;
883           if (!p2->m_edge.m_s) toBeDeleted.push_back(p2->m_edge.m_index);
884         }
885       }
886     }
887 
888   for (i = 0; i < toBeDeleted.size(); i++) eraseIntersection(toBeDeleted[i]);
889 
890   m_areValidRegions = false;
891   //}
892 
893   if (doComputeRegions) computeRegions();
894   // print(m_intersectionData->m_intList, "C:\\temp\\intersectionDopoLoad.txt");
895 }
896 
897 //-----------------------------------------------------------------------------
898 
eraseIntersection(int index)899 void TVectorImage::Imp::eraseIntersection(int index) {
900   vector<int> autocloseStrokes;
901   doEraseIntersection(index, &autocloseStrokes);
902 
903   for (UINT i = 0; i < autocloseStrokes.size(); i++) {
904     doEraseIntersection(autocloseStrokes[i]);
905     assert(autocloseStrokes[i] < 0);
906     m_intersectionData->m_autocloseMap.erase(autocloseStrokes[i]);
907   }
908 }
909 //-----------------------------------------------------------------------------
910 
findNearestIntersection(VIList<Intersection> & interList)911 static void findNearestIntersection(VIList<Intersection> &interList) {
912   Intersection *p1;
913   IntersectedStroke *p2;
914 
915   for (p1 = interList.first(); p1; p1 = p1->next()) {
916     for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next()) {
917       if (p2->m_nextIntersection)  // already set
918         continue;
919 
920       int versus      = (p2->m_gettingOut) ? 1 : -1;
921       double minDelta = (std::numeric_limits<double>::max)();
922       Intersection *pp1, *p1Res;
923       IntersectedStroke *pp2, *p2Res;
924 
925       for (pp1 = p1; pp1; pp1 = pp1->next()) {
926         if (pp1 == p1)
927           pp2 = p2, pp2 = pp2->next();
928         else
929           pp2 = pp1->m_strokeList.first();
930 
931         for (; pp2; pp2 = pp2->next()) {
932           if (pp2->m_edge.m_index == p2->m_edge.m_index &&
933               pp2->m_gettingOut == !p2->m_gettingOut) {
934             double delta = versus * (pp2->m_edge.m_w0 - p2->m_edge.m_w0);
935 
936             if (delta > 0 && delta < minDelta) {
937               p1Res    = pp1;
938               p2Res    = pp2;
939               minDelta = delta;
940             }
941           }
942         }
943       }
944 
945       if (minDelta != (std::numeric_limits<double>::max)()) {
946         p2Res->m_nextIntersection = p1;
947         p2Res->m_nextStroke       = p2;
948         p2Res->m_edge.m_w1        = p2->m_edge.m_w0;
949         p2->m_nextIntersection    = p1Res;
950         p2->m_nextStroke          = p2Res;
951         p2->m_edge.m_w1           = p2Res->m_edge.m_w0;
952         p1->m_numInter++;
953         p1Res->m_numInter++;
954       }
955     }
956   }
957 }
958 
959 //-----------------------------------------------------------------------------
960 void markDeadIntersections(VIList<Intersection> &intList, Intersection *p);
961 
962 // questa funzione "cuscinetto" serve perche crashava il compilatore in
963 // release!!!
markDeadIntersectionsRic(VIList<Intersection> & intList,Intersection * p)964 void inline markDeadIntersectionsRic(VIList<Intersection> &intList,
965                                      Intersection *p) {
966   markDeadIntersections(intList, p);
967 }
968 
969 //-----------------------------------------------------------------------------
970 
markDeadIntersections(VIList<Intersection> & intList,Intersection * p)971 void markDeadIntersections(VIList<Intersection> &intList, Intersection *p) {
972   IntersectedStroke *p1 = p->m_strokeList.first();
973   if (!p1) return;
974 
975   if (p->m_numInter == 1) {
976     while (p1 && !!p1->m_nextIntersection) {
977       p1 = p1->next();
978     }
979     // assert(p1);
980     if (!p1) return;
981 
982     Intersection *nextInt         = p1->m_nextIntersection;
983     IntersectedStroke *nextStroke = p1->m_nextStroke;
984 
985     p->m_numInter          = 0;
986     p1->m_nextIntersection = 0;
987 
988     if (nextInt /*&& !nextStroke->m_dead*/) {
989       nextInt->m_numInter--;
990       nextStroke->m_nextIntersection = 0;
991       markDeadIntersectionsRic(intList, nextInt);
992     }
993   } else if (p->m_numInter == 2)  // intersezione finta (forse)
994   {
995     while (p1 && !p1->m_nextIntersection) p1 = p1->next();
996     assert(p1);
997     if (!p1) return;
998     IntersectedStroke *p2 = p1->next();
999 
1000     while (p2 && !p2->m_nextIntersection) p2 = p2->next();
1001 
1002     assert(p2);
1003     if (!p2) return;
1004 
1005     if (p1->m_edge.m_s == p2->m_edge.m_s &&
1006         p1->m_edge.m_w0 == p2->m_edge.m_w0)  // intersezione finta
1007     {
1008       IntersectedStroke *pp1, *pp2;
1009       assert(p1->m_nextIntersection && p2->m_nextIntersection);
1010 
1011       pp1 = p1->m_nextStroke;
1012       pp2 = p2->m_nextStroke;
1013 
1014       pp2->m_edge.m_w1 = pp1->m_edge.m_w0;
1015       pp1->m_edge.m_w1 = pp2->m_edge.m_w0;
1016 
1017       // if (iit1!=0)
1018       pp1->m_nextStroke = pp2;
1019       // if (iit2!=0)
1020       pp2->m_nextStroke = pp1;
1021       // if (iit1!=0)
1022       pp1->m_nextIntersection = p2->m_nextIntersection;
1023       // if (iit2!=0)
1024       pp2->m_nextIntersection = p1->m_nextIntersection;
1025 
1026       p->m_numInter          = 0;
1027       p1->m_nextIntersection = p2->m_nextIntersection = 0;
1028     }
1029   }
1030 }
1031 
1032 //-----------------------------------------------------------------------------
1033 
1034 // se cross val era 0, cerco di spostarmi un po' su w per vedere come sono
1035 // orientate le tangenti agli stroke...
nearCrossVal(TStroke * s0,double w0,TStroke * s1,double w1)1036 static double nearCrossVal(TStroke *s0, double w0, TStroke *s1, double w1) {
1037   double ltot0 = s0->getLength();
1038   double ltot1 = s1->getLength();
1039   double dl    = std::min(ltot1, ltot0) / 1000;
1040 
1041   double crossVal, dl0 = dl, dl1 = dl;
1042 
1043   TPointD p0, p1;
1044   int count = 0;
1045 
1046   if (w0 == 1.0) dl0 = -dl0;
1047   if (w1 == 1.0) dl1 = -dl1;
1048 
1049   double l0 = s0->getLength(w0) + dl0;
1050   double l1 = s1->getLength(w1) + dl1;
1051 
1052   do {
1053     p0       = s0->getSpeed(s0->getParameterAtLength(l0));
1054     p1       = s1->getSpeed(s1->getParameterAtLength(l1));
1055     crossVal = cross(p0, p1);
1056     l0 += dl0, l1 += dl1;
1057     count++;
1058   } while (areAlmostEqual(crossVal, 0.0) &&
1059            ((dl0 > 0 && l0 < ltot0) || (dl0 < 0 && l0 > 0)) &&
1060            ((dl1 > 0 && l1 < ltot1) || (dl1 < 0 && l1 > 0)));
1061   return crossVal;
1062 }
1063 
1064 //-----------------------------------------------------------------------------
1065 
insertBranch(Intersection & in,IntersectedStroke & item,bool gettingOut)1066 inline void insertBranch(Intersection &in, IntersectedStroke &item,
1067                          bool gettingOut) {
1068   if (item.m_edge.m_w0 != (gettingOut ? 1.0 : 0.0)) {
1069     item.m_gettingOut = gettingOut;
1070     in.m_strokeList.pushBack(new IntersectedStroke(item));
1071   }
1072 }
1073 
1074 //-----------------------------------------------------------------------------
1075 
getAngle(const TPointD & p0,const TPointD & p1)1076 static double getAngle(const TPointD &p0, const TPointD &p1) {
1077   double angle1 = atan2(p0.x, p0.y) * M_180_PI;
1078   double angle2 = atan2(p1.x, p1.y) * M_180_PI;
1079 
1080   if (angle1 < 0) angle1 = 360 + angle1;
1081   if (angle2 < 0) angle2 = 360 + angle2;
1082 
1083   return (angle2 - angle1) < 0 ? 360 + angle2 - angle1 : angle2 - angle1;
1084 }
1085 
1086 //-----------------------------------------------------------------------------
1087 // nel caso l'angolo tra due stroke in un certo w sia nullo,
1088 // si va un po' avanti per vedere come sono orientate....
getNearAngle(const TStroke * s1,double w1,bool out1,const TStroke * s2,double w2,bool out2)1089 static double getNearAngle(const TStroke *s1, double w1, bool out1,
1090                            const TStroke *s2, double w2, bool out2) {
1091   bool verse1  = (out1 && w1 < 1) || (!out1 && w1 == 0);
1092   bool verse2  = (out2 && w2 < 1) || (!out2 && w2 == 0);
1093   double ltot1 = s1->getLength();
1094   double ltot2 = s2->getLength();
1095   double l1    = s1->getLength(w1);
1096   double l2    = s2->getLength(w2);
1097   double dl    = min(ltot1, ltot2) / 1000;
1098   double dl1   = verse1 ? dl : -dl;
1099   double dl2   = verse2 ? dl : -dl;
1100 
1101   while (((verse1 && l1 < ltot1) || (!verse1 && l1 > 0)) &&
1102          ((verse2 && l2 < ltot2) || (!verse2 && l2 > 0))) {
1103     l1 += dl1;
1104     l2 += dl2;
1105     TPointD p1   = (out1 ? 1 : -1) * s1->getSpeed(s1->getParameterAtLength(l1));
1106     TPointD p2   = (out2 ? 1 : -1) * s2->getSpeed(s2->getParameterAtLength(l2));
1107     double angle = getAngle(p1, p2);
1108     if (!areAlmostEqual(angle, 0, 1e-9)) return angle;
1109   }
1110   return 0;
1111 }
1112 
1113 //-----------------------------------------------------------------------------
1114 
makeEdgeIntersection(Intersection & interList,IntersectedStroke & item1,IntersectedStroke & item2,const TPointD & p1a,const TPointD & p1b,const TPointD & p2a,const TPointD & p2b)1115 static bool makeEdgeIntersection(Intersection &interList,
1116                                  IntersectedStroke &item1,
1117                                  IntersectedStroke &item2, const TPointD &p1a,
1118                                  const TPointD &p1b, const TPointD &p2a,
1119                                  const TPointD &p2b) {
1120   double angle1 = getAngle(p1a, p1b);
1121   double angle2 = getAngle(p1a, p2a);
1122   double angle3 = getAngle(p1a, p2b);
1123   double angle;
1124 
1125   bool eraseP1b = false, eraseP2a = false, eraseP2b = false;
1126 
1127   if (areAlmostEqual(angle1, 0, 1e-9)) {
1128     angle1 = getNearAngle(item1.m_edge.m_s, item1.m_edge.m_w0, true,
1129                           item1.m_edge.m_s, item1.m_edge.m_w0, false);
1130     if (areAlmostEqual(angle1, 1e-9)) eraseP1b = true;
1131   }
1132   if (areAlmostEqual(angle2, 0, 1e-9)) {
1133     angle2 = getNearAngle(item1.m_edge.m_s, item1.m_edge.m_w0, true,
1134                           item2.m_edge.m_s, item2.m_edge.m_w0, true);
1135     if (areAlmostEqual(angle2, 1e-9)) eraseP2a = true;
1136   }
1137   if (areAlmostEqual(angle3, 0, 1e-9)) {
1138     angle3 = getNearAngle(item1.m_edge.m_s, item1.m_edge.m_w0, true,
1139                           item2.m_edge.m_s, item2.m_edge.m_w0, false);
1140     if (areAlmostEqual(angle3, 1e-9)) eraseP2b = true;
1141   }
1142 
1143   if (areAlmostEqual(angle1, angle2, 1e-9)) {
1144     angle = getNearAngle(item1.m_edge.m_s, item1.m_edge.m_w0, false,
1145                          item2.m_edge.m_s, item2.m_edge.m_w0, true);
1146     if (angle != 0) {
1147       angle2 += angle;
1148       if (angle2 > 360) angle2 -= 360;
1149     } else
1150       eraseP2a = true;
1151   }
1152   if (areAlmostEqual(angle1, angle3, 1e-9)) {
1153     angle = getNearAngle(item1.m_edge.m_s, item1.m_edge.m_w0, false,
1154                          item2.m_edge.m_s, item2.m_edge.m_w0, false);
1155     if (angle != 0) {
1156       angle3 += angle;
1157       if (angle3 > 360) angle3 -= 360;
1158     } else
1159       eraseP2b = true;
1160   }
1161   if (areAlmostEqual(angle2, angle3, 1e-9)) {
1162     angle = getNearAngle(item1.m_edge.m_s, item1.m_edge.m_w0, false,
1163                          item2.m_edge.m_s, item2.m_edge.m_w0, true);
1164     if (angle != 0) {
1165       angle3 += angle;
1166       if (angle3 > 360) angle3 -= 360;
1167     } else
1168       eraseP2b = true;
1169   }
1170 
1171   int fac =
1172       (angle1 < angle2) | ((angle1 < angle3) << 1) | ((angle2 < angle3) << 2);
1173 
1174   switch (fac) {
1175   case 0:  // p1a p2b p2a p1b
1176     insertBranch(interList, item1, true);
1177     if (!eraseP2b) insertBranch(interList, item2, false);
1178     if (!eraseP2a) insertBranch(interList, item2, true);
1179     if (!eraseP1b) insertBranch(interList, item1, false);
1180     break;
1181   case 1:  // p1a p2b p1b p2a
1182     insertBranch(interList, item1, true);
1183     if (!eraseP2b) insertBranch(interList, item2, false);
1184     if (!eraseP1b) insertBranch(interList, item1, false);
1185     if (!eraseP2a) insertBranch(interList, item2, true);
1186     break;
1187   case 2:
1188     assert(false);
1189     break;
1190   case 3:  // p1a p1b p2b p2a
1191     insertBranch(interList, item1, true);
1192     if (!eraseP1b) insertBranch(interList, item1, false);
1193     if (!eraseP2b) insertBranch(interList, item2, false);
1194     if (!eraseP2a) insertBranch(interList, item2, true);
1195     break;
1196   case 4:  // p1a p2a p2b p1b
1197     insertBranch(interList, item1, true);
1198     if (!eraseP2a) insertBranch(interList, item2, true);
1199     if (!eraseP2b) insertBranch(interList, item2, false);
1200     if (!eraseP1b) insertBranch(interList, item1, false);
1201     break;
1202   case 5:
1203     assert(false);
1204     break;
1205   case 6:  // p1a p2a p1b p2b
1206     insertBranch(interList, item1, true);
1207     if (!eraseP2a) insertBranch(interList, item2, true);
1208     if (!eraseP1b) insertBranch(interList, item1, false);
1209     if (!eraseP2b) insertBranch(interList, item2, false);
1210     break;
1211   case 7:  // p1a p1b p2a p2b
1212     insertBranch(interList, item1, true);
1213     if (!eraseP1b) insertBranch(interList, item1, false);
1214     if (!eraseP2a) insertBranch(interList, item2, true);
1215     if (!eraseP2b) insertBranch(interList, item2, false);
1216     break;
1217   default:
1218     assert(false);
1219   }
1220 
1221   return true;
1222 }
1223 
1224 //-----------------------------------------------------------------------------
1225 
makeIntersection(IntersectionData & intData,const vector<VIStroke * > & s,int ii,int jj,DoublePair inter,int strokeSize,Intersection & interList)1226 static bool makeIntersection(IntersectionData &intData,
1227                              const vector<VIStroke *> &s, int ii, int jj,
1228                              DoublePair inter, int strokeSize,
1229                              Intersection &interList) {
1230   IntersectedStroke item1, item2;
1231 
1232   interList.m_intersection = s[ii]->m_s->getPoint(inter.first);
1233 
1234   item1.m_edge.m_w0 = inter.first;
1235   item2.m_edge.m_w0 = inter.second;
1236 
1237   if (ii >= 0 && ii < strokeSize) {
1238     item1.m_edge.m_s     = s[ii]->m_s;
1239     item1.m_edge.m_index = ii;
1240   } else {
1241     if (ii < 0) {
1242       item1.m_edge.m_s     = intData.m_autocloseMap[ii]->m_s;
1243       item1.m_edge.m_index = ii;
1244     } else {
1245       item1.m_edge.m_s     = s[ii]->m_s;
1246       item1.m_edge.m_index = -(ii + intData.maxAutocloseId * 100000);
1247       intData.m_autocloseMap[item1.m_edge.m_index] = s[ii];
1248     }
1249   }
1250 
1251   if (jj >= 0 && jj < strokeSize) {
1252     item2.m_edge.m_s     = s[jj]->m_s;
1253     item2.m_edge.m_index = jj;
1254   } else {
1255     if (jj < 0) {
1256       item2.m_edge.m_s     = intData.m_autocloseMap[jj]->m_s;
1257       item2.m_edge.m_index = jj;
1258     } else {
1259       item2.m_edge.m_s     = s[jj]->m_s;
1260       item2.m_edge.m_index = -(jj + intData.maxAutocloseId * 100000);
1261       intData.m_autocloseMap[item2.m_edge.m_index] = s[jj];
1262     }
1263   }
1264 
1265   bool reversed = false;
1266 
1267   TPointD p0, p0b, p1, p1b;
1268 
1269   bool ret1 = item1.m_edge.m_s->getSpeedTwoValues(item1.m_edge.m_w0, p0, p0b);
1270   bool ret2 = item2.m_edge.m_s->getSpeedTwoValues(item2.m_edge.m_w0, p1, p1b);
1271 
1272   if (ret1 || ret2)  // punto angoloso!!!!
1273     return makeEdgeIntersection(interList, item1, item2, p0, p0b, p1, p1b);
1274 
1275   double crossVal = cross(p0, p1);
1276 
1277   // crossVal = cross(p0, p1);
1278 
1279   if (areAlmostEqual(crossVal, 0.0)) {
1280     bool endpoint1 = (item1.m_edge.m_w0 == 0.0 || item1.m_edge.m_w0 == 1.0);
1281     bool endpoint2 = (item2.m_edge.m_w0 == 0.0 || item2.m_edge.m_w0 == 1.0);
1282     if (endpoint1 && endpoint2 && ((p0.x * p1.x >= 0 && p0.y * p1.y >= 0 &&
1283                                     item1.m_edge.m_w0 != item2.m_edge.m_w0) ||
1284                                    (p0.x * p1.x <= 0 && p0.y * p1.y <= 0 &&
1285                                     item1.m_edge.m_w0 == item2.m_edge.m_w0)))
1286     // due endpoint a 180 gradi;metto
1287     {
1288       item1.m_gettingOut = (item1.m_edge.m_w0 == 0.0);
1289       interList.m_strokeList.pushBack(new IntersectedStroke(item1));
1290       item2.m_gettingOut = (item2.m_edge.m_w0 == 0.0);
1291       interList.m_strokeList.pushBack(new IntersectedStroke(item2));
1292       return true;
1293     }
1294     // crossVal = nearCrossVal(item1.m_edge.m_s, item1.m_edge.m_w0,
1295     // item2.m_edge.m_s, item2.m_edge.m_w0);
1296     // if (areAlmostEqual(crossVal, 0.0))
1297     // return false;
1298     return makeEdgeIntersection(interList, item1, item2, p0, p0b, p1, p1b);
1299   }
1300 
1301   if (crossVal > 0)
1302     reversed = true;  // std::reverse(interList.m_strokeList.begin(),
1303                       // interList.m_strokeList.end());
1304 
1305   if (item1.m_edge.m_w0 != 1.0) {
1306     item1.m_gettingOut = true;
1307     interList.m_strokeList.pushBack(new IntersectedStroke(item1));
1308   }
1309   if (item2.m_edge.m_w0 != (reversed ? 0.0 : 1.0)) {
1310     item2.m_gettingOut = !reversed;
1311     interList.m_strokeList.pushBack(new IntersectedStroke(item2));
1312   }
1313   if (item1.m_edge.m_w0 != 0.0) {
1314     item1.m_gettingOut = false;
1315     interList.m_strokeList.pushBack(new IntersectedStroke(item1));
1316   }
1317   if (item2.m_edge.m_w0 != (reversed ? 1.0 : 0.0)) {
1318     item2.m_gettingOut = reversed;
1319     interList.m_strokeList.pushBack(new IntersectedStroke(item2));
1320   }
1321 
1322   return true;
1323 }
1324 
1325 //-----------------------------------------------------------------------------
1326 /*
1327 void checkAuto(const vector<VIStroke*>& s)
1328 {
1329 for (int i=0; i<(int)s.size(); i++)
1330 for (int j=i+1; j<(int)s.size(); j++)
1331   if (s[i]->m_s->getChunkCount()==1 && s[j]->m_s->getChunkCount()==1) //se ha
1332 una sola quadratica, probabilmente e' un autoclose.
1333           {
1334                 const TThickQuadratic*q = s[i]->m_s->getChunk(0);
1335                 const TThickQuadratic*p = s[j]->m_s->getChunk(0);
1336 
1337                 if (areAlmostEqual(q->getP0(), p->getP0(), 1e-2) &&
1338 areAlmostEqual(q->getP2(), p->getP2(), 1e-2))
1339                   assert(!"eccolo!");
1340                 if (areAlmostEqual(q->getP0(), p->getP2(), 1e-2) &&
1341 areAlmostEqual(q->getP2(), p->getP0(), 1e-2))
1342                   assert(!"eccolo!");
1343     }
1344 }
1345 */
1346 //-----------------------------------------------------------------------------
1347 
addAutocloseIntersection(IntersectionData & intData,vector<VIStroke * > & s,int ii,int jj,double w0,double w1,int strokeSize,bool isVectorized)1348 static bool addAutocloseIntersection(IntersectionData &intData,
1349                                      vector<VIStroke *> &s, int ii, int jj,
1350                                      double w0, double w1, int strokeSize,
1351                                      bool isVectorized) {
1352   assert(s[ii]->m_groupId == s[jj]->m_groupId);
1353 
1354   Intersection *rp = intData.m_intList.last();
1355 
1356   assert(w0 >= 0.0 && w0 <= 1.0);
1357   assert(w1 >= 0.0 && w1 <= 1.0);
1358 
1359   for (; rp; rp = rp->prev())  // evito di fare la connessione, se gia' ce
1360                                // ne e' una simile tra le stesse due stroke
1361   {
1362     if (rp->m_strokeList.size() < 2) continue;
1363     IntersectedStroke *ps = rp->m_strokeList.first();
1364     int s0                = ps->m_edge.m_index;
1365     if (s0 < 0) continue;
1366     double ww0 = ps->m_edge.m_w0;
1367     ps         = ps->next();
1368     if (ps->m_edge.m_index == s0 && ps->m_edge.m_w0 == ww0) {
1369       ps = ps->next();
1370       if (!ps) continue;
1371     }
1372     int s1 = ps->m_edge.m_index;
1373     if (s1 < 0) continue;
1374     double ww1 = ps->m_edge.m_w0;
1375 
1376     if (!((s0 == ii && s1 == jj) || (s0 == jj && s1 == ii))) continue;
1377 
1378     if (s0 == ii && areAlmostEqual(w0, ww0, 0.1) &&
1379         areAlmostEqual(w1, ww1, 0.1))
1380       return false;
1381     else if (s1 == ii && areAlmostEqual(w0, ww1, 0.1) &&
1382              areAlmostEqual(w1, ww0, 0.1))
1383       return false;
1384   }
1385 
1386   vector<TPointD> v;
1387   v.push_back(s[ii]->m_s->getPoint(w0));
1388   v.push_back(s[jj]->m_s->getPoint(w1));
1389   if (v[0] == v[1])  // le stroke si intersecano , ma la fottuta funzione
1390                      // intersect non ha trovato l'intersezione(tipicamente,
1391                      // questo accade agli estremi)!!!
1392   {
1393     addIntersection(intData, s, ii, jj, DoublePair(w0, w1), strokeSize,
1394                     isVectorized);
1395     return true;
1396   }
1397 
1398   // se gia e' stato messo questo autoclose, evito
1399   for (int i = 0; i < (int)s.size(); i++)
1400     if (s[i]->m_s->getChunkCount() ==
1401         1)  // se ha una sola quadratica, probabilmente e' un autoclose.
1402     {
1403       const TThickQuadratic *q = s[i]->m_s->getChunk(0);
1404 
1405       if ((areAlmostEqual(q->getP0(), v[0], 1e-2) &&
1406               areAlmostEqual(q->getP2(), v[1], 1e-2)) ||
1407           (areAlmostEqual(q->getP0(), v[1], 1e-2) &&
1408               areAlmostEqual(q->getP2(), v[0], 1e-2))) {
1409         return true;
1410         addIntersection(intData, s, i, ii, DoublePair(0.0, w0), strokeSize,
1411                         isVectorized);
1412         addIntersection(intData, s, i, jj, DoublePair(1.0, w1), strokeSize,
1413                         isVectorized);
1414         return true;
1415       }
1416     }
1417   assert(s[ii]->m_groupId == s[jj]->m_groupId);
1418 
1419   s.push_back(new VIStroke(new TStroke(v), s[ii]->m_groupId));
1420   addIntersection(intData, s, s.size() - 1, ii, DoublePair(0.0, w0), strokeSize,
1421                   isVectorized);
1422   addIntersection(intData, s, s.size() - 1, jj, DoublePair(1.0, w1), strokeSize,
1423                   isVectorized);
1424   return true;
1425 }
1426 
1427 //-----------------------------------------------------------------------------
1428 
1429 // double g_autocloseTolerance = c_newAutocloseTolerance;
1430 
isCloseEnoughP2P(double facMin,double facMax,TStroke * s1,double w0,TStroke * s2,double w1)1431 static bool isCloseEnoughP2P(double facMin, double facMax, TStroke *s1,
1432                              double w0, TStroke *s2, double w1) {
1433   double autoDistMin, autoDistMax;
1434 
1435   TThickPoint p0 = s1->getThickPoint(w0);
1436   TThickPoint p1 = s2->getThickPoint(w1);
1437   double dist2;
1438 
1439   dist2 = tdistance2(p0, p1);
1440 
1441   /*!when closing beetween a normal stroke and a 0-thickness stroke (very
1442    * typical) the thin  one is assumed to have same thickness of the other*/
1443   if (p0.thick == 0)
1444     p0.thick = p1.thick;
1445   else if (p1.thick == 0)
1446     p1.thick = p0.thick;
1447   if (facMin == 0) {
1448     autoDistMin = 0;
1449     autoDistMax =
1450         std::max(-2.0, facMax * (p0.thick + p1.thick) * (p0.thick + p1.thick));
1451     if (autoDistMax < 0.0000001)  //! for strokes without thickness, I connect
1452                                   //! for distances less than min between 2.5
1453                                   //! and half of the length of the stroke)
1454     {
1455       double len1 = s1->getLength();
1456       double len2 = s2->getLength();
1457       autoDistMax =
1458           facMax * std::min({2.5, len1 * len1 / (2 * 2), len2 * len2 / (2 * 2),
1459                              100.0 /*dummyVal*/});
1460     }
1461   } else {
1462     autoDistMin =
1463         std::max(-2.0, facMin * (p0.thick + p1.thick) * (p0.thick + p1.thick));
1464     if (autoDistMin < 0.0000001)  //! for strokes without thickness, I connect
1465                                   //! for distances less than min between 2.5
1466                                   //! and half of the length of the stroke)
1467     {
1468       double len1 = s1->getLength();
1469       double len2 = s2->getLength();
1470       autoDistMin =
1471           facMax * std::min({2.5, len1 * len1 / (2 * 2), len2 * len2 / (2 * 2),
1472                              100.0 /*dummyVal*/});
1473     }
1474 
1475     autoDistMax = autoDistMin + (facMax - facMin) * (facMax - facMin);
1476   }
1477 
1478   if (dist2 < autoDistMin || dist2 > autoDistMax) return false;
1479 
1480   // if (dist2<=std::max(2.0,
1481   // g_autocloseTolerance*(p0.thick+p1.thick)*(p0.thick+p1.thick))) //0.01 tiene
1482   // conto di quando thick==0
1483   if (s1 == s2) {
1484     TRectD r = s1->getBBox();  // se e' un autoclose su una stroke piccolissima,
1485                                // creerebbe uan area trascurabile, ignoro
1486     if (fabs(r.x1 - r.x0) < 2 && fabs(r.y1 - r.y0) < 2) return false;
1487   }
1488   return true;
1489 }
1490 
1491 //---------------------------------------------------------------------------------------------------------------------
1492 /*
1493 bool makePoint2PointConnections(double factor, vector<VIStroke*>& s,
1494                              int ii, bool isIStartPoint,
1495                              int jj, bool isJStartPoint, IntersectionData&
1496 intData,
1497                               int strokeSize)
1498 {
1499 double w0 = (isIStartPoint?0.0:1.0);
1500 double w1 = (isJStartPoint?0.0:1.0);
1501 if (isCloseEnoughP2P(factor, s[ii]->m_s, w0,  s[jj]->m_s, w1))
1502   return addAutocloseIntersection(intData, s, ii, jj, w0, w1, strokeSize);
1503 return false;
1504 }
1505 */
1506 //-----------------------------------------------------------------------------
1507 
getCurlW(TStroke * s,bool isBegin)1508 static double getCurlW(TStroke *s,
1509                        bool isBegin)  // trova il punto di split su una
1510                                       // stroke, in prossimita di un
1511                                       // ricciolo;
1512 // un ricciolo c'e' se la curva ha un  min o max relativo su x seguito da uno su
1513 // y, o viceversa.
1514 {
1515   int numChunks = s->getChunkCount();
1516   double dx2, dx1 = 0, dy2, dy1 = 0;
1517   int i = 0;
1518   for (i = 0; i < numChunks; i++) {
1519     const TQuadratic *q = s->getChunk(isBegin ? i : numChunks - 1 - i);
1520     dy2                 = q->getP1().y - q->getP0().y;
1521     if (dy1 * dy2 < 0) break;
1522     dy1 = dy2;
1523     dy2 = q->getP2().y - q->getP1().y;
1524     if (dy1 * dy2 < 0) break;
1525     dy1 = dy2;
1526   }
1527   if (i == numChunks) return -1;
1528 
1529   int maxMin0 = isBegin ? i : numChunks - 1 - i;
1530   int j       = 0;
1531   for (j = 0; j < numChunks; j++) {
1532     const TQuadratic *q = s->getChunk(isBegin ? j : numChunks - 1 - j);
1533     dx2                 = q->getP1().x - q->getP0().x;
1534     if (dx1 * dx2 < 0) break;
1535     dx1 = dx2;
1536     dx2 = q->getP2().x - q->getP1().x;
1537     if (dx1 * dx2 < 0) break;
1538     dx1 = dx2;
1539   }
1540   if (j == numChunks) return -1;
1541 
1542   int maxMin1 = isBegin ? j : numChunks - 1 - j;
1543 
1544   return getWfromChunkAndT(
1545       s, isBegin ? std::max(maxMin0, maxMin1) : std::min(maxMin0, maxMin1),
1546       isBegin ? 1.0 : 0.0);
1547 }
1548 
1549 #ifdef Levo
1550 bool lastIsX = false, lastIsY = false;
1551 for (int i = 0; i < numChunks; i++) {
1552   const TThickQuadratic *q = s->getChunk(isBegin ? i : numChunks - 1 - i);
1553   if ((q->getP0().y < q->getP1().y &&
1554        q->getP2().y <
1555            q->getP1().y) ||  // la quadratica ha un minimo o massimo relativo
1556       (q->getP0().y > q->getP1().y && q->getP2().y > q->getP1().y)) {
1557     double w = getWfromChunkAndT(s, isBegin ? i : numChunks - 1 - i,
1558                                  isBegin ? 1.0 : 0.0);
1559     if (lastIsX)  // e' il secondo min o max relativo
1560       return w;
1561     lastIsX = false;
1562     lastIsY = true;
1563 
1564   } else if ((q->getP0().x < q->getP1().x &&
1565               q->getP2().x <
1566                   q->getP1()
1567                       .x) ||  // la quadratica ha un minimo o massimo relativo
1568              (q->getP0().x > q->getP1().x && q->getP2().x > q->getP1().x)) {
1569     double w = getWfromChunkAndT(s, isBegin ? i : numChunks - 1 - i,
1570                                  isBegin ? 1.0 : 0.0);
1571     if (lastIsY)  // e' il secondo min o max relativo
1572       return w;
1573     lastIsX = true;
1574     lastIsY = false;
1575   }
1576 }
1577 
1578 return -1;
1579 }
1580 
1581 #endif
1582 //-----------------------------------------------------------------------------
1583 
1584 static bool isCloseEnoughP2L(double facMin, double facMax, TStroke *s1,
1585                              double w1, TStroke *s2, double &w) {
1586   if (s1->isSelfLoop()) return false;
1587 
1588   TThickPoint p0 = s1->getThickPoint(w1);
1589   double t, dist2;
1590   int index;
1591   TStroke sAux, *sComp;
1592 
1593   if (s1 == s2)  // per trovare le intersezioni con una stroke e se stessa, si
1594                  // toglie il
1595   // pezzo di stroke di cui si cercano vicinanze fino alla prima curva
1596   {
1597     double w = getCurlW(s1, w1 == 0.0);
1598     if (w == -1) return false;
1599 
1600     split<TStroke>(*s1, std::min(1 - w1, w), std::max(1 - w1, w), sAux);
1601     sComp = &sAux;
1602   } else
1603     sComp = s2;
1604 
1605   if (sComp->getNearestChunk(p0, t, index, dist2) && dist2 > 0) {
1606     if (s1 == s2) {
1607       double dummy;
1608       s2->getNearestChunk(sComp->getChunk(index)->getPoint(t), t, index, dummy);
1609     }
1610 
1611     // if (areAlmostEqual(w, 0.0, 0.05) || areAlmostEqual(w, 1.0, 0.05))
1612     //  return; //se w e' vicino ad un estremo, rientra nell'autoclose point to
1613     //  point
1614 
1615     // if (s[jj]->m_s->getLength(w)<=s[jj]->m_s->getThickPoint(0).thick ||
1616     //    s[jj]->m_s->getLength(w, 1)<=s[jj]->m_s->getThickPoint(1).thick)
1617     //  return;
1618 
1619     TThickPoint p1 = s2->getChunk(index)->getThickPoint(t);
1620 
1621     /*!when closing beetween a normal stroke and a 0-thickness stroke (very
1622      * typical) the thin  one is assumed to have same thickness of the other*/
1623     if (p0.thick == 0)
1624       p0.thick = p1.thick;
1625     else if (p1.thick == 0)
1626       p1.thick = p0.thick;
1627     double autoDistMin, autoDistMax;
1628     if (facMin == 0) {
1629       autoDistMin = 0;
1630       autoDistMax = std::max(
1631           -2.0, (facMax + 0.7) * (p0.thick + p1.thick) * (p0.thick + p1.thick));
1632       if (autoDistMax < 0.0000001)  //! for strokes without thickness, I connect
1633                                     //! for distances less than min between 2.5
1634                                     //! and half of the length of the pointing
1635                                     //! stroke)
1636       {
1637         double len1 = s1->getLength();
1638         autoDistMax = facMax * std::min(2.5, len1 * len1 / (2 * 2));
1639       }
1640     } else {
1641       autoDistMin = std::max(
1642           -2.0, (facMin + 0.7) * (p0.thick + p1.thick) * (p0.thick + p1.thick));
1643       if (autoDistMin < 0.0000001)  //! for strokes without thickness, I connect
1644                                     //! for distances less than min between 2.5
1645                                     //! and half of the length of the pointing
1646                                     //! stroke)
1647       {
1648         double len1 = s1->getLength();
1649         autoDistMin = facMax * std::min(2.5, len1 * len1 / (2 * 2));
1650       }
1651 
1652       autoDistMax =
1653           autoDistMin + (facMax - facMin + 0.7) * (facMax - facMin + 0.7);
1654     }
1655 
1656     // double autoDistMin = std::max(-2.0,
1657     // facMin==0?0:(facMin+0.7)*(p0.thick+p1.thick)*(p0.thick+p1.thick));
1658     // double autoDistMax = std::max(-2.0,
1659     // (facMax+0.7)*(p0.thick+p1.thick)*(p0.thick+p1.thick));
1660 
1661     if (dist2 < autoDistMin || dist2 > autoDistMax) return false;
1662 
1663     // if (dist2<=(std::max(2.0,
1664     // (g_autocloseTolerance+0.7)*(p0.thick+p1.thick)*(p0.thick+p1.thick))))
1665     // //0.01 tiene conto di quando thick==0
1666 
1667     w = getWfromChunkAndT(s2, index, t);
1668     return true;
1669   }
1670   return false;
1671 }
1672 
1673 //-------------------------------------------------------------
1674 /*
1675 void makePoint2LineConnection(double factor, vector<VIStroke*>& s, int ii, int
1676 jj, bool isBegin, IntersectionData& intData,
1677                     int strokeSize)
1678 {
1679 double w1 = isBegin?0.0: 1.0;
1680 
1681 TStroke* s1 = s[ii]->m_s;
1682 TStroke* s2 = s[jj]->m_s;
1683 double w;
1684 if (isCloseEnoughP2L(factor, s1, w1,  s2, w))
1685   addAutocloseIntersection(intData, s, ii, jj, w1, w, strokeSize);
1686 }
1687 */
1688 //-----------------------------------------------------------------------------
1689 
1690 namespace {
1691 
1692 inline bool isSegment(const TStroke &s) {
1693   vector<TThickPoint> v;
1694   s.getControlPoints(v);
1695   UINT n = v.size();
1696   if (areAlmostEqual(v[n - 1].x, v[0].x, 1e-4)) {
1697     for (UINT i = 1; i < n - 1; i++)
1698       if (!areAlmostEqual(v[i].x, v[0].x, 1e-4)) return false;
1699   } else if (areAlmostEqual(v[n - 1].y, v[0].y, 1e-4)) {
1700     for (UINT i = 1; i < n - 1; i++)
1701       if (!areAlmostEqual(v[i].y, v[0].y, 1e-4)) return false;
1702   } else {
1703     double fac = (v[n - 1].y - v[0].y) / (v[n - 1].x - v[0].x);
1704     for (UINT i = 1; i < n - 1; i++)
1705       if (!areAlmostEqual((v[i].y - v[0].y) / (v[i].x - v[0].x), fac, 1e-4))
1706         return false;
1707   }
1708   return true;
1709 }
1710 
1711 //---------------------------------------------------------------------------------
1712 /*
1713 bool segmentAlreadyExist(const TVectorImageP& vi, const TPointD& p1, const
1714 TPointD& p2)
1715 {
1716 for (UINT i=0; i<vi->getStrokeCount(); i++)
1717   {
1718   TStroke*s = vi->getStroke(i);
1719   if (!s->getBBox().contains(p1) || !s->getBBox().contains(p2))
1720     continue;
1721   if (((areAlmostEqual(s->getPoint(0.0), p1, 1e-4) &&
1722 areAlmostEqual(s->getPoint(1.0), p2, 1e-4)) ||
1723       (areAlmostEqual(s->getPoint(0.0), p2, 1e-4) &&
1724 areAlmostEqual(s->getPoint(1.0), p1, 1e-4))) &&
1725        isSegment(*s))
1726     return true;
1727 
1728   }
1729 return false;
1730 }
1731 */
1732 //----------------------------------------------------------------------------------
1733 
1734 bool segmentAlreadyPresent(const TVectorImageP &vi, const TPointD &p1,
1735                            const TPointD &p2) {
1736   for (UINT i = 0; i < vi->getStrokeCount(); i++) {
1737     TStroke *s = vi->getStroke(i);
1738     if (((areAlmostEqual(s->getPoint(0.0), p1, 1e-4) &&
1739           areAlmostEqual(s->getPoint(1.0), p2, 1e-4)) ||
1740          (areAlmostEqual(s->getPoint(0.0), p2, 1e-4) &&
1741           areAlmostEqual(s->getPoint(1.0), p1, 1e-4))) &&
1742         isSegment(*s))
1743       return true;
1744   }
1745   return false;
1746   /*
1747 for (UINT i=0; i<vi->getStrokeCount(); i++)
1748 {
1749 TStroke* s = vi->getStroke(i);
1750 
1751 if (s->getChunkCount()!=1)
1752 continue;
1753 if (areAlmostEqual((TPointD)s->getControlPoint(0),                           p1,
1754 1e-2) &&
1755 areAlmostEqual((TPointD)s->getControlPoint(s->getControlPointCount()-1), p2,
1756 1e-2))
1757 return true;
1758 }
1759 
1760 return false;
1761 */
1762 }
1763 
1764 void getClosingSegments(TL2LAutocloser &l2lautocloser, double facMin,
1765                         double facMax, TStroke *s1, TStroke *s2,
1766                         vector<DoublePair> *intersections,
1767                         vector<std::pair<double, double>> &segments) {
1768   bool ret1 = false, ret2 = false, ret3 = false, ret4 = false;
1769 #define L2LAUTOCLOSE
1770 #ifdef L2LAUTOCLOSE
1771   double thickmax2 = s1->getMaxThickness() + s2->getMaxThickness();
1772   thickmax2 *= thickmax2;
1773   if (facMin == 0)
1774     l2lautocloser.setMaxDistance2((facMax + 0.7) * thickmax2);
1775   else
1776     l2lautocloser.setMaxDistance2((facMax + 0.7) * thickmax2 +
1777                                   (facMax - facMin + 0.7) *
1778                                       (facMax - facMin + 0.7));
1779 
1780   std::vector<TL2LAutocloser::Segment> l2lSegments;
1781   if (intersections)
1782     l2lautocloser.search(l2lSegments, s1, s2, *intersections);
1783   else
1784     l2lautocloser.search(l2lSegments, s1, s2);
1785 
1786   for (UINT i = 0; i < l2lSegments.size(); i++) {
1787     TL2LAutocloser::Segment &seg = l2lSegments[i];
1788     double autoDistMin, autoDistMax;
1789     if (facMin == 0) {
1790       autoDistMin = 0;
1791       autoDistMax = (facMax + 0.7) * (seg.p0.thick + seg.p1.thick) *
1792                     (seg.p0.thick + seg.p1.thick);
1793     } else {
1794       autoDistMin = (facMin + 0.7) * (seg.p0.thick + seg.p1.thick) *
1795                     (seg.p0.thick + seg.p1.thick);
1796       autoDistMax =
1797           autoDistMin + (facMax - facMin + 0.7) * (facMax - facMin + 0.7);
1798     }
1799 
1800     if (seg.dist2 > autoDistMin && seg.dist2 < autoDistMax)
1801       segments.push_back(std::pair<double, double>(seg.w0, seg.w1));
1802   }
1803 #endif
1804 
1805   if (s1->isSelfLoop() && s2->isSelfLoop()) return;
1806 
1807   if (!s1->isSelfLoop() && !s2->isSelfLoop()) {
1808     if ((ret1 = isCloseEnoughP2P(facMin, facMax, s1, 0.0, s2, 1.0)))
1809       segments.push_back(std::pair<double, double>(0.0, 1.0));
1810 
1811     if (s1 != s2) {
1812       if ((ret2 = isCloseEnoughP2P(facMin, facMax, s1, 0.0, s2, 0.0)))
1813         segments.push_back(std::pair<double, double>(0.0, 0.0));
1814       if ((ret3 = isCloseEnoughP2P(facMin, facMax, s1, 1.0, s2, 0.0)))
1815         segments.push_back(std::pair<double, double>(1.0, 0.0));
1816       if ((ret4 = isCloseEnoughP2P(facMin, facMax, s1, 1.0, s2, 1.0)))
1817         segments.push_back(std::pair<double, double>(1.0, 1.0));
1818     }
1819   }
1820 
1821   double w;
1822   if (!ret1 && !ret2 && isCloseEnoughP2L(facMin, facMax, s1, 0.0, s2, w))
1823     segments.push_back(std::pair<double, double>(0.0, w));
1824   if (!ret1 && !ret4 && isCloseEnoughP2L(facMin, facMax, s2, 1.0, s1, w))
1825     segments.push_back(std::pair<double, double>(w, 1.0));
1826 
1827   if (s1 != s2) {
1828     if (!ret2 && !ret3 && isCloseEnoughP2L(facMin, facMax, s2, 0.0, s1, w))
1829       segments.push_back(std::pair<double, double>(w, 0.0));
1830     if (!ret3 && !ret4 && isCloseEnoughP2L(facMin, facMax, s1, 1.0, s2, w))
1831       segments.push_back(std::pair<double, double>(1.0, w));
1832   }
1833 }
1834 
1835 }  // namaspace
1836 
1837 //---------------------------------------------------------------------------------
1838 
1839 void getClosingPoints(const TRectD &rect, double fac, const TVectorImageP &vi,
1840                       vector<pair<int, double>> &startPoints,
1841                       vector<pair<int, double>> &endPoints) {
1842   UINT strokeCount = vi->getStrokeCount();
1843   TL2LAutocloser l2lautocloser;
1844 
1845   for (UINT i = 0; i < strokeCount; i++) {
1846     TStroke *s1 = vi->getStroke(i);
1847     if (!rect.overlaps(s1->getBBox())) continue;
1848     if (s1->getChunkCount() == 1) continue;
1849 
1850     for (UINT j = i; j < strokeCount; j++) {
1851       TStroke *s2 = vi->getStroke(j);
1852 
1853       if (!rect.overlaps(s1->getBBox())) continue;
1854       if (s2->getChunkCount() == 1) continue;
1855 
1856 #ifdef NEW_REGION_FILL
1857       double autoTol = 0;
1858 #else
1859       double autoTol = vi->getAutocloseTolerance();
1860 #endif
1861 
1862       double enlarge1 =
1863           (autoTol + 0.7) *
1864               (s1->getMaxThickness() > 0 ? s1->getMaxThickness() : 2.5) +
1865           fac;
1866       double enlarge2 =
1867           (autoTol + 0.7) *
1868               (s2->getMaxThickness() > 0 ? s2->getMaxThickness() : 2.5) +
1869           fac;
1870 
1871       if (i != j &&
1872           !s1->getBBox().enlarge(enlarge1).overlaps(
1873               s2->getBBox().enlarge(enlarge2)))
1874         continue;
1875 
1876       vector<std::pair<double, double>> segments;
1877       getClosingSegments(l2lautocloser, autoTol, autoTol + fac, s1, s2, 0,
1878                          segments);
1879       for (UINT k = 0; k < segments.size(); k++) {
1880         TPointD p1 = s1->getPoint(segments[k].first);
1881         TPointD p2 = s2->getPoint(segments[k].second);
1882         if (rect.contains(p1) && rect.contains(p2)) {
1883           if (segmentAlreadyPresent(vi, p1, p2)) continue;
1884           startPoints.push_back(pair<int, double>(i, segments[k].first));
1885           endPoints.push_back(pair<int, double>(j, segments[k].second));
1886         }
1887       }
1888     }
1889   }
1890 }
1891 
1892 //-------------------------------------------------------------------------------------------------------
1893 
1894 static void autoclose(double factor, vector<VIStroke *> &s, int ii, int jj,
1895                       IntersectionData &IntData, int strokeSize,
1896                       TL2LAutocloser &l2lautocloser,
1897                       vector<DoublePair> *intersections, bool isVectorized) {
1898   vector<std::pair<double, double>> segments;
1899   getClosingSegments(l2lautocloser, 0, factor, s[ii]->m_s, s[jj]->m_s,
1900                      intersections, segments);
1901 
1902   for (UINT i = 0; i < segments.size(); i++)
1903     addAutocloseIntersection(IntData, s, ii, jj, segments[i].first,
1904                              segments[i].second, strokeSize, isVectorized);
1905 }
1906 
1907 //------------------------------------------------------------------------------------------------------
1908 #ifdef LEVO
1909 void autoclose(double factor, vector<VIStroke *> &s, int ii, int jj,
1910                IntersectionData &IntData, int strokeSize) {
1911   bool ret1 = false, ret2 = false, ret3 = false, ret4 = false;
1912 
1913   if (s[ii]->m_s->isSelfLoop() && s[jj]->m_s->isSelfLoop()) return;
1914 
1915   if (!s[ii]->m_s->isSelfLoop() && !s[jj]->m_s->isSelfLoop()) {
1916     ret1 = makePoint2PointConnections(factor, s, ii, true, jj, false, IntData,
1917                                       strokeSize);
1918 
1919     if (ii != jj) {
1920       ret2 = makePoint2PointConnections(factor, s, ii, true, jj, true, IntData,
1921                                         strokeSize);
1922       ret3 = makePoint2PointConnections(factor, s, ii, false, jj, true, IntData,
1923                                         strokeSize);
1924       ret4 = makePoint2PointConnections(factor, s, ii, false, jj, false,
1925                                         IntData, strokeSize);
1926     }
1927   }
1928 
1929   if (!ret1 && !ret2)
1930     makePoint2LineConnection(factor, s, ii, jj, true, IntData, strokeSize);
1931   if (!ret1 && !ret4)
1932     makePoint2LineConnection(factor, s, jj, ii, false, IntData, strokeSize);
1933   if (ii != jj) {
1934     if (!ret2 && !ret3)
1935       makePoint2LineConnection(factor, s, jj, ii, true, IntData, strokeSize);
1936     if (!ret3 && !ret4)
1937       makePoint2LineConnection(factor, s, ii, jj, false, IntData, strokeSize);
1938   }
1939 }
1940 
1941 #endif
1942 
1943 //-----------------------------------------------------------------------------
1944 
1945 TPointD inline getTangent(const IntersectedStroke &item) {
1946   return (item.m_gettingOut ? 1 : -1) *
1947          item.m_edge.m_s->getSpeed(item.m_edge.m_w0, item.m_gettingOut);
1948 }
1949 
1950 //-----------------------------------------------------------------------------
1951 
1952 static void addBranch(IntersectionData &intData,
1953                       VIList<IntersectedStroke> &strokeList,
1954                       const vector<VIStroke *> &s, int ii, double w,
1955                       int strokeSize, bool gettingOut) {
1956   IntersectedStroke *p1, *p2;
1957   TPointD tanRef, lastTan;
1958 
1959   IntersectedStroke *item = new IntersectedStroke();
1960 
1961   if (ii < 0) {
1962     item->m_edge.m_s     = intData.m_autocloseMap[ii]->m_s;
1963     item->m_edge.m_index = ii;
1964   } else {
1965     item->m_edge.m_s = s[ii]->m_s;
1966     if (ii < strokeSize)
1967       item->m_edge.m_index = ii;
1968     else {
1969       item->m_edge.m_index = -(ii + intData.maxAutocloseId * 100000);
1970       intData.m_autocloseMap[item->m_edge.m_index] = s[ii];
1971     }
1972   }
1973 
1974   item->m_edge.m_w0  = w;
1975   item->m_gettingOut = gettingOut;
1976 
1977   /*
1978 if (strokeList.size()==2) //potrebbero essere orientati male; due branch possono
1979 stare come vogliono, ma col terzo no.
1980 {
1981 TPointD tan2 = getTangent(strokeList.back());
1982 TPointD aux= getTangent(*(strokeList.begin()));
1983 double crossVal = cross(aux, tan2);
1984 if (areAlmostEqual(aux, tan2, 1e-3))
1985     return;
1986 
1987   if (crossVal>0)
1988 {
1989           std::reverse(strokeList.begin(), strokeList.end());
1990 //tan2 = getTangent(strokeList.back());
1991           }
1992 }
1993 */
1994   /*
1995 if (areAlmostEqual(lastCross, 0.0) && tan1.x*tan2.x>=0 && tan1.y*tan2.y>=0)
1996 //significa angolo tra tangenti nullo
1997     {
1998           crossVal =  nearCrossVal(item.m_edge.m_s, item.m_edge.m_w0,
1999 strokeList.back().m_edge.m_s, strokeList.back().m_edge.m_w0);
2000 if (areAlmostEqual(crossVal, 0.0))
2001             return;
2002           if (!strokeList.back().m_gettingOut)
2003             crossVal = -crossVal;
2004 }
2005 */
2006 
2007   tanRef  = getTangent(*item);
2008   lastTan = getTangent(*strokeList.last());
2009   /*
2010 for (it=strokeList.begin(); it!=strokeList.end(); ++it)
2011 {
2012   TPointD curTan = getTangent(*it);
2013 double angle0 = getAngle(lastTan, curTan);
2014 double angle1 = getAngle(lastTan, tanRef);
2015 
2016 if (areAlmostEqual(angle0, angle1, 1e-8))
2017     {
2018           double angle = getNearAngle( it->m_edge.m_s,  it->m_edge.m_w0,
2019 it->m_gettingOut,
2020                                       item.m_edge.m_s, item.m_edge.m_w0,
2021 item.m_gettingOut);
2022 angle1 += angle; if (angle1>360) angle1-=360;
2023 }
2024 
2025 if (angle1<angle0)
2026 {
2027 strokeList.insert(it, item);
2028 return;
2029 }
2030   lastTan=curTan;
2031 }*/
2032 
2033   p2 = strokeList.last();
2034 
2035   for (p1 = strokeList.first(); p1; p1 = p1->next()) {
2036     TPointD curTan = getTangent(*p1);
2037     double angle0  = getAngle(lastTan, curTan);
2038     double angle1  = getAngle(lastTan, tanRef);
2039 
2040     if (areAlmostEqual(angle1, 0, 1e-8)) {
2041       double angle =
2042           getNearAngle(p2->m_edge.m_s, p2->m_edge.m_w0, p2->m_gettingOut,
2043                        item->m_edge.m_s, item->m_edge.m_w0, item->m_gettingOut);
2044       angle1 += angle;
2045       if (angle1 > 360) angle1 -= 360;
2046     }
2047 
2048     if (areAlmostEqual(angle0, angle1, 1e-8)) {
2049       double angle =
2050           getNearAngle(p1->m_edge.m_s, p1->m_edge.m_w0, p1->m_gettingOut,
2051                        item->m_edge.m_s, item->m_edge.m_w0, item->m_gettingOut);
2052       angle1 += angle;
2053       if (angle1 > 360) angle1 -= 360;
2054     }
2055 
2056     if (angle1 < angle0) {
2057       strokeList.insert(p1, item);
2058       return;
2059     }
2060     lastTan = curTan;
2061     p2      = p1;
2062   }
2063 
2064   // assert(!"add branch: can't find where to insert!");
2065   strokeList.pushBack(item);
2066 }
2067 
2068 //-----------------------------------------------------------------------------
2069 
2070 static void addBranches(IntersectionData &intData, Intersection &intersection,
2071                         const vector<VIStroke *> &s, int ii, int jj,
2072                         DoublePair intersectionPair, int strokeSize) {
2073   bool foundS1 = false, foundS2 = false;
2074   IntersectedStroke *p;
2075 
2076   assert(!intersection.m_strokeList.empty());
2077 
2078   for (p = intersection.m_strokeList.first(); p; p = p->next()) {
2079     if ((ii >= 0 && p->m_edge.m_s == s[ii]->m_s &&
2080          p->m_edge.m_w0 == intersectionPair.first) ||
2081         (ii < 0 && p->m_edge.m_index == ii &&
2082          p->m_edge.m_w0 == intersectionPair.first))
2083       foundS1 = true;
2084     if ((jj >= 0 && p->m_edge.m_s == s[jj]->m_s &&
2085          p->m_edge.m_w0 == intersectionPair.second) ||
2086         (jj < 0 && p->m_edge.m_index == jj &&
2087          p->m_edge.m_w0 == intersectionPair.second))
2088       foundS2 = true;
2089   }
2090 
2091   if (foundS1 && foundS2) {
2092     /*
2093 //errore!(vedi commento sotto) possono essere un sacco di intersezioni
2094 coincidenti se passano per l'estremo di una quad
2095 //significa che ci sono due intersezioni coincidenti. cioe' due stroke tangenti.
2096 quindi devo invertire l'ordine di due branch enlla rosa dei branch.
2097 list<IntersectedStroke>::iterator it1, it2;
2098 it1=intersection.m_strokeList.begin();
2099 it2 = it1; it2++;
2100 for (; it2!=intersection.m_strokeList.end(); ++it1, ++it2)
2101 {
2102 if ((*it1).m_gettingOut!=(*it2).m_gettingOut &&((*it1).m_edge.m_index==jj &&
2103 (*it2).m_edge.m_index==ii) ||
2104         ((*it1).m_edge.m_index==ii && (*it2).m_edge.m_index==jj))
2105 {
2106             IntersectedStroke& el1 = (*it1);
2107             IntersectedStroke& el2 = (*it2);
2108 IntersectedStroke app;
2109             app = el1;
2110             el1=el2;
2111             el2=app;
2112             break;
2113 }
2114     }
2115 */
2116     return;
2117   }
2118 
2119   if (!foundS1) {
2120     if (intersectionPair.first != 1)
2121       addBranch(intData, intersection.m_strokeList, s, ii,
2122                 intersectionPair.first, strokeSize, true);
2123     if (intersectionPair.first != 0)
2124       addBranch(intData, intersection.m_strokeList, s, ii,
2125                 intersectionPair.first, strokeSize, false);
2126     // assert(intersection.m_strokeList.size()-size>0);
2127   }
2128   if (!foundS2) {
2129     if (intersectionPair.second != 1)
2130       addBranch(intData, intersection.m_strokeList, s, jj,
2131                 intersectionPair.second, strokeSize, true);
2132     if (intersectionPair.second != 0)
2133       addBranch(intData, intersection.m_strokeList, s, jj,
2134                 intersectionPair.second, strokeSize, false);
2135     // intersection.m_numInter+=intersection.m_strokeList.size()-size;
2136     // assert(intersection.m_strokeList.size()-size>0);
2137   }
2138 }
2139 
2140 //-----------------------------------------------------------------------------
2141 
2142 static void addIntersections(IntersectionData &intData,
2143                              const vector<VIStroke *> &s, int ii, int jj,
2144                              vector<DoublePair> &intersections, int strokeSize,
2145                              bool isVectorized) {
2146   for (int k = 0; k < (int)intersections.size(); k++) {
2147     if (ii >= strokeSize && (areAlmostEqual(intersections[k].first, 0.0) ||
2148                              areAlmostEqual(intersections[k].first, 1.0)))
2149       continue;
2150     if (jj >= strokeSize && (areAlmostEqual(intersections[k].second, 0.0) ||
2151                              areAlmostEqual(intersections[k].second, 1.0)))
2152       continue;
2153 
2154     addIntersection(intData, s, ii, jj, intersections[k], strokeSize,
2155                     isVectorized);
2156   }
2157 }
2158 
2159 //-----------------------------------------------------------------------------
2160 
2161 inline double truncate(double x) {
2162   x += 1.0;
2163   TUINT32 *l = (TUINT32 *)&x;
2164 
2165 #if TNZ_LITTLE_ENDIAN
2166   l[0] &= 0xFFE00000;
2167 #else
2168   l[1] &= 0xFFE00000;
2169 #endif
2170 
2171   return x - 1.0;
2172 }
2173 
2174 //-----------------------------------------------------------------------------
2175 
2176 void addIntersection(IntersectionData &intData, const vector<VIStroke *> &s,
2177                      int ii, int jj, DoublePair intersection, int strokeSize,
2178                      bool isVectorized) {
2179   Intersection *p;
2180   TPointD point;
2181 
2182   assert(ii < 0 || jj < 0 || s[ii]->m_groupId == s[jj]->m_groupId);
2183 
2184   // UINT iw;
2185   // iw = ((UINT)(intersection.first*0x3fffffff));
2186   // intersection.first = truncate(intersection.first);
2187   // iw = (UINT)(intersection.second*0x3fffffff);
2188 
2189   // intersection.second = truncate(intersection.second);
2190 
2191   if (areAlmostEqual(intersection.first, 0.0, 1e-5))
2192     intersection.first = 0.0;
2193   else if (areAlmostEqual(intersection.first, 1.0, 1e-5))
2194     intersection.first = 1.0;
2195 
2196   if (areAlmostEqual(intersection.second, 0.0, 1e-5))
2197     intersection.second = 0.0;
2198   else if (areAlmostEqual(intersection.second, 1.0, 1e-5))
2199     intersection.second = 1.0;
2200 
2201   point = s[ii]->m_s->getPoint(intersection.first);
2202 
2203   for (p = intData.m_intList.first(); p; p = p->next())
2204     if (p->m_intersection == point ||
2205         (isVectorized &&
2206          areAlmostEqual(
2207              p->m_intersection, point,
2208              1e-2)))  // devono essere rigorosamente uguali, altrimenti
2209     // il calcolo dell'ordine dei rami con le tangenti sballa
2210     {
2211       addBranches(intData, *p, s, ii, jj, intersection, strokeSize);
2212       return;
2213     }
2214 
2215   intData.m_intList.pushBack(new Intersection);
2216 
2217   if (!makeIntersection(intData, s, ii, jj, intersection, strokeSize,
2218                         *intData.m_intList.last()))
2219     intData.m_intList.erase(intData.m_intList.last());
2220 }
2221 
2222 //-----------------------------------------------------------------------------
2223 
2224 void TVectorImage::Imp::findIntersections() {
2225   vector<VIStroke *> &strokeArray = m_strokes;
2226   IntersectionData &intData       = *m_intersectionData;
2227   int strokeSize                  = (int)strokeArray.size();
2228   int i, j;
2229   bool isVectorized = (m_autocloseTolerance < 0);
2230 
2231   assert(intData.m_intersectedStrokeArray.empty());
2232 #define AUTOCLOSE_ATTIVO
2233 #ifdef AUTOCLOSE_ATTIVO
2234   intData.maxAutocloseId++;
2235 
2236   map<int, VIStroke *>::iterator it, it_b = intData.m_autocloseMap.begin();
2237   map<int, VIStroke *>::iterator it_e = intData.m_autocloseMap.end();
2238 
2239   // prima cerco le intersezioni tra nuove strokes e vecchi autoclose
2240   for (i = 0; i < strokeSize; i++) {
2241     TStroke *s1 = strokeArray[i]->m_s;
2242     if (!strokeArray[i]->m_isNewForFill || strokeArray[i]->m_isPoint) continue;
2243 
2244     TRectD bBox   = s1->getBBox();
2245     double thick2 = s1->getThickPoint(0).thick *
2246                     2.1;  // 2.1 instead of 2.0, for usual problems of approx...
2247     if (bBox.getLx() <= thick2 && bBox.getLy() <= thick2) {
2248       strokeArray[i]->m_isPoint = true;
2249       continue;
2250     }
2251 
2252     roundStroke(s1);
2253 
2254     for (it = it_b; it != it_e; ++it) {
2255       if (!it->second || it->second->m_groupId != strokeArray[i]->m_groupId)
2256         continue;
2257 
2258       TStroke *s2 = it->second->m_s;
2259       vector<DoublePair> parIntersections;
2260       if (intersect(s1, s2, parIntersections, true))
2261         addIntersections(intData, strokeArray, i, it->first, parIntersections,
2262                          strokeSize, isVectorized);
2263     }
2264   }
2265 #endif
2266 
2267   // poi,  intersezioni tra stroke, in cui almeno uno dei due deve essere nuovo
2268 
2269   map<pair<int, int>, vector<DoublePair>> intersectionMap;
2270 
2271   for (i = 0; i < strokeSize; i++) {
2272     TStroke *s1 = strokeArray[i]->m_s;
2273     if (strokeArray[i]->m_isPoint) continue;
2274     for (j = i; j < strokeSize /*&& (strokeArray[i]->getBBox().x1>=
2275                                   strokeArray[j]->getBBox().x0)*/
2276          ;
2277          j++) {
2278       TStroke *s2 = strokeArray[j]->m_s;
2279 
2280       if (strokeArray[j]->m_isPoint ||
2281           !(strokeArray[i]->m_isNewForFill || strokeArray[j]->m_isNewForFill))
2282         continue;
2283       if (strokeArray[i]->m_groupId != strokeArray[j]->m_groupId) continue;
2284 
2285       vector<DoublePair> parIntersections;
2286       if (s1->getBBox().overlaps(s2->getBBox())) {
2287         UINT size = intData.m_intList.size();
2288 
2289         if (intersect(s1, s2, parIntersections, false)) {
2290           // if (i==0 && j==1) parIntersections.erase(parIntersections.begin());
2291           intersectionMap[pair<int, int>(i, j)] = parIntersections;
2292           addIntersections(intData, strokeArray, i, j, parIntersections,
2293                            strokeSize, isVectorized);
2294         } else
2295           intersectionMap[pair<int, int>(i, j)] = vector<DoublePair>();
2296 
2297         if (!strokeArray[i]->m_isNewForFill &&
2298             size != intData.m_intList.size() &&
2299             !strokeArray[i]->m_edgeList.empty())  // aggiunte nuove intersezioni
2300         {
2301           intData.m_intersectedStrokeArray.push_back(IntersectedStrokeEdges(i));
2302           list<TEdge *> &_list =
2303               intData.m_intersectedStrokeArray.back().m_edgeList;
2304           list<TEdge *>::const_iterator it;
2305           for (it = strokeArray[i]->m_edgeList.begin();
2306                it != strokeArray[i]->m_edgeList.end(); ++it)
2307             _list.push_back(new TEdge(**it, false));
2308         }
2309       }
2310     }
2311   }
2312 
2313 #ifdef AUTOCLOSE_ATTIVO
2314   TL2LAutocloser l2lautocloser;
2315 
2316   for (i = 0; i < strokeSize; i++) {
2317     TStroke *s1 = strokeArray[i]->m_s;
2318     if (strokeArray[i]->m_isPoint) continue;
2319     for (j = i; j < strokeSize; j++) {
2320       if (strokeArray[i]->m_groupId != strokeArray[j]->m_groupId) continue;
2321 
2322       TStroke *s2 = strokeArray[j]->m_s;
2323       if (strokeArray[j]->m_isPoint) continue;
2324       if (!(strokeArray[i]->m_isNewForFill || strokeArray[j]->m_isNewForFill))
2325         continue;
2326 
2327       double enlarge1 =
2328           (m_autocloseTolerance + 0.7) *
2329           (s1->getMaxThickness() > 0 ? s1->getMaxThickness() : 2.5);
2330       double enlarge2 =
2331           (m_autocloseTolerance + 0.7) *
2332           (s2->getMaxThickness() > 0 ? s2->getMaxThickness() : 2.5);
2333 
2334       if (s1->getBBox().enlarge(enlarge1).overlaps(
2335               s2->getBBox().enlarge(enlarge2))) {
2336         map<pair<int, int>, vector<DoublePair>>::iterator it =
2337             intersectionMap.find(pair<int, int>(i, j));
2338         if (it == intersectionMap.end())
2339           autoclose(m_autocloseTolerance, strokeArray, i, j, intData,
2340                     strokeSize, l2lautocloser, 0, isVectorized);
2341         else
2342           autoclose(m_autocloseTolerance, strokeArray, i, j, intData,
2343                     strokeSize, l2lautocloser, &(it->second), isVectorized);
2344       }
2345     }
2346     strokeArray[i]->m_isNewForFill = false;
2347   }
2348 #endif
2349 
2350   for (i = 0; i < strokeSize; i++) {
2351     list<TEdge *>::iterator it, it_b = strokeArray[i]->m_edgeList.begin(),
2352                                 it_e = strokeArray[i]->m_edgeList.end();
2353     for (it = it_b; it != it_e; ++it)
2354       if ((*it)->m_toBeDeleted == 1) delete *it;
2355 
2356     strokeArray[i]->m_edgeList.clear();
2357   }
2358 
2359   // si devono cercare le intersezioni con i segmenti aggiunti per l'autoclose
2360 
2361   for (i = strokeSize; i < (int)strokeArray.size(); ++i) {
2362     TStroke *s1 = strokeArray[i]->m_s;
2363 
2364     for (j = i + 1; j < (int)strokeArray.size();
2365          ++j)  // intersezione segmento-segmento
2366     {
2367       if (strokeArray[i]->m_groupId != strokeArray[j]->m_groupId) continue;
2368 
2369       TStroke *s2 = strokeArray[j]->m_s;
2370       vector<DoublePair> parIntersections;
2371       if (intersect(s1, s2, parIntersections, true))
2372         addIntersections(intData, strokeArray, i, j, parIntersections,
2373                          strokeSize, isVectorized);
2374     }
2375     for (j = 0; j < strokeSize; ++j)  // intersezione segmento-curva
2376     {
2377       if (strokeArray[j]->m_isPoint) continue;
2378       if (strokeArray[i]->m_groupId != strokeArray[j]->m_groupId) continue;
2379 
2380       TStroke *s2 = strokeArray[j]->m_s;
2381       vector<DoublePair> parIntersections;
2382       if (intersect(s1, s2, parIntersections, true))
2383         addIntersections(intData, strokeArray, i, j, parIntersections,
2384                          strokeSize, isVectorized);
2385     }
2386   }
2387 }
2388 
2389 // la struttura delle intersezioni viene poi visitata per trovare
2390 // i link tra un'intersezione e la successiva
2391 
2392 //-----------------------------------------------------------------------------
2393 void TVectorImage::Imp::deleteRegionsData() {
2394   clearPointerContainer(m_strokes);
2395   clearPointerContainer(m_regions);
2396 
2397   Intersection *p1;
2398   for (p1 = m_intersectionData->m_intList.first(); p1; p1 = p1->next())
2399     p1->m_strokeList.clear();
2400   m_intersectionData->m_intList.clear();
2401   delete m_intersectionData;
2402   m_intersectionData = 0;
2403 }
2404 
2405 void TVectorImage::Imp::initRegionsData() {
2406   m_intersectionData = new IntersectionData();
2407 }
2408 
2409 //-----------------------------------------------------------------------------
2410 
2411 int TVectorImage::Imp::computeIntersections() {
2412   Intersection *p1;
2413   IntersectionData &intData = *m_intersectionData;
2414   int strokeSize            = (int)m_strokes.size();
2415 
2416   findIntersections();
2417 
2418   findNearestIntersection(intData.m_intList);
2419 
2420   // for (it1=intData.m_intList.begin(); it1!=intData.m_intList.end();) //la
2421   // faccio qui, e non nella eraseIntersection. vedi commento li'.
2422   eraseDeadIntersections();
2423 
2424   for (p1 = intData.m_intList.first(); p1; p1 = p1->next())
2425     markDeadIntersections(intData.m_intList, p1);
2426 
2427   // checkInterList(intData.m_intList);
2428   return strokeSize;
2429 }
2430 
2431 //-----------------------------------------------------------------------------
2432 
2433 /*
2434 void endPointIntersect(const TStroke* s0, const TStroke* s1, vector<DoublePair>&
2435 parIntersections)
2436 {
2437 TPointD p00 = s0->getPoint(0);
2438 TPointD p11 = s1->getPoint(1);
2439 if (tdistance2(p00, p11)< 2*0.06*0.06)
2440   parIntersections.push_back(DoublePair(0, 1));
2441 
2442 if (s0==s1)
2443   return;
2444 
2445 TPointD p01 = s0->getPoint(1);
2446 TPointD p10 = s1->getPoint(0);
2447 
2448 if (tdistance2(p00, p10)< 2*0.06*0.06)
2449   parIntersections.push_back(DoublePair(0, 0));
2450 if (tdistance2(p01, p10)< 2*0.06*0.06)
2451   parIntersections.push_back(DoublePair(1, 0));
2452 if (tdistance2(p01, p11)< 2*0.06*0.06)
2453   parIntersections.push_back(DoublePair(1, 1));
2454 
2455 }
2456 */
2457 //-----------------------------------------------------------------------------
2458 
2459 //-----------------------------------------------------------------------------
2460 
2461 // Trova una possibile regione data una lista di punti di intersezione
2462 static TRegion *findRegion(VIList<Intersection> &intList, Intersection *p1,
2463                            IntersectedStroke *p2, bool minimizeEdges) {
2464   TRegion *r    = new TRegion();
2465   int currStyle = 0;
2466 
2467   IntersectedStroke *pStart = p2;
2468   Intersection *nextp1;
2469   IntersectedStroke *nextp2;
2470 
2471   // Cicla finche' t2 non punta ad uno stroke gia' visitato
2472   while (!p2->m_visited) {
2473     p2->m_visited = true;
2474 
2475     // Ciclo finche' lo stroke puntato da it2 non ha un successivo punto di
2476     // intersezione
2477     do {
2478       p2 = p2->next();
2479       if (!p2)  // uso la lista come se fosse circolare
2480         p2 = p1->m_strokeList.first();
2481       if (!p2) {
2482         delete r;
2483         return 0;
2484       }
2485 
2486     } while (!p2->m_nextIntersection);
2487 
2488     nextp1 = p2->m_nextIntersection;
2489     nextp2 = p2->m_nextStroke;
2490 
2491     // Viene controllato e sistemato lo stile degli stroke
2492     if (p2->m_edge.m_styleId != 0) {
2493       if (currStyle == 0)
2494         currStyle = p2->m_edge.m_styleId;
2495       else if (p2->m_edge.m_styleId != currStyle) {
2496         currStyle = p2->m_edge.m_styleId;
2497         for (UINT i                = 0; i < r->getEdgeCount(); i++)
2498           r->getEdge(i)->m_styleId = currStyle;
2499       }
2500     } else
2501       p2->m_edge.m_styleId = currStyle;
2502 
2503     // Aggiunge lo stroke puntato da p2 alla regione
2504     r->addEdge(&p2->m_edge, minimizeEdges);
2505 
2506     if (nextp2 == pStart) return r;
2507 
2508     p1 = nextp1;
2509     p2 = nextp2;
2510   }
2511 
2512   delete r;
2513   return 0;
2514 }
2515 
2516 //-----------------------------------------------------------------------------
2517 /*
2518 bool areEqualRegions(const TRegion& r1, const TRegion& r2)
2519 {
2520 if (r1.getBBox()!=r2.getBBox())
2521   return false;
2522 if (r1.getEdgeCount()!=r2.getEdgeCount())
2523   return false;
2524 
2525 for (UINT i=0; i<r1.getEdgeCount(); i++)
2526   {
2527   TEdge *e1 = r1.getEdge(i);
2528   for (j=0; j<r2.getEdgeCount(); j++)
2529     {
2530     TEdge *e2 = r2.getEdge(j);
2531     if (e1->m_s==e2->m_s &&
2532         std::min(e1->m_w0, e1->m_w1)==std::min(e2->m_w0, e2->m_w1) &&
2533         std::max(e1->m_w0, e1->m_w1)==std::max(e2->m_w0, e2->m_w1))
2534       {
2535       if (e1->m_styleId && !e2->m_styleId)
2536         e2->m_styleId=e1->m_styleId;
2537       else if (e2->m_styleId && !e1->m_styleId)
2538         e1->m_styleId=e2->m_styleId;
2539       break;
2540       }
2541     }
2542   if (j==r2.getEdgeCount())  //e1 non e' uguale a nessun edge di r2
2543     return false;
2544   }
2545 
2546 
2547 return true;
2548 }
2549 */
2550 //-----------------------------------------------------------------------------
2551 /*
2552 bool isMetaRegion(const TRegion& r1, const TRegion& r2)
2553 {
2554 if (areEqualRegions(r1, r2))
2555     return true;
2556 
2557 for (UINT i=0; i<r1.getRegionCount(); i++)
2558   {
2559   if (isMetaRegion(*r1.getRegion(i), r2))
2560     return true;
2561   }
2562 return false;
2563 }
2564 
2565 //-----------------------------------------------------------------------------
2566 
2567 bool isMetaRegion(const vector<TRegion*>& m_regions, const TRegion& r)
2568 {
2569 for (UINT i=0; i<m_regions.size(); i++)
2570   if (isMetaRegion(*(m_regions[i]), r))
2571     return true;
2572 
2573 return false;
2574 }
2575 
2576 //-----------------------------------------------------------------------------
2577 */
2578 
2579 class TRegionClockWiseFormula final : public TRegionFeatureFormula {
2580 private:
2581   double m_quasiArea;
2582 
2583 public:
2584   TRegionClockWiseFormula() : m_quasiArea(0) {}
2585 
2586   void update(const TPointD &p1, const TPointD &p2) override {
2587     m_quasiArea += (p2.y + p1.y) * (p1.x - p2.x);
2588   }
2589 
2590   bool isClockwise() { return m_quasiArea > 0.1; }
2591 };
2592 
2593 //----------------------------------------------------------------------------------------------
2594 
2595 void computeRegionFeature(const TRegion &r, TRegionFeatureFormula &formula) {
2596   TPointD p, pOld /*, pAux*/;
2597   int pointAdded = 0;
2598 
2599   int size = r.getEdgeCount();
2600 
2601   if (size == 0) return;
2602 
2603   // if (size<2)
2604   //  return !isMetaRegion(regions, r);
2605 
2606   int firstControlPoint;
2607   int lastControlPoint;
2608 
2609   TEdge *e = r.getEdge(size - 1);
2610   pOld     = e->m_s->getPoint(e->m_w1);
2611 
2612   for (int i = 0; i < size; i++) {
2613     TEdge *e          = r.getEdge(i);
2614     TStroke *s        = e->m_s;
2615     firstControlPoint = s->getControlPointIndexAfterParameter(e->m_w0);
2616     lastControlPoint  = s->getControlPointIndexAfterParameter(e->m_w1);
2617 
2618     p = s->getPoint(e->m_w0);
2619     formula.update(pOld, p);
2620 
2621     pOld = p;
2622     pointAdded++;
2623     if (firstControlPoint <= lastControlPoint) {
2624       if (firstControlPoint & 0x1) firstControlPoint++;
2625       if (lastControlPoint - firstControlPoint <=
2626           2)  /// per evitare di avere troppi pochi punti....
2627       {
2628         p = s->getPoint(0.333333 * e->m_w0 + 0.666666 * e->m_w1);
2629         formula.update(pOld, p);
2630 
2631         pOld = p;
2632         pointAdded++;
2633         p = s->getPoint(0.666666 * e->m_w0 + 0.333333 * e->m_w1);
2634         formula.update(pOld, p);
2635 
2636         pOld = p;
2637         pointAdded++;
2638       } else
2639         for (int j = firstControlPoint; j < lastControlPoint; j += 2) {
2640           p = s->getControlPoint(j);
2641           formula.update(pOld, p);
2642           pOld = p;
2643           pointAdded++;
2644         }
2645     } else {
2646       firstControlPoint--;  // this case, getControlPointIndexBEFOREParameter
2647       lastControlPoint--;
2648       if (firstControlPoint & 0x1) firstControlPoint--;
2649       if (firstControlPoint - lastControlPoint <=
2650           2)  /// per evitare di avere troppi pochi punti....
2651       {
2652         p = s->getPoint(0.333333 * e->m_w0 + 0.666666 * e->m_w1);
2653         formula.update(pOld, p);
2654         pOld = p;
2655         pointAdded++;
2656         p = s->getPoint(0.666666 * e->m_w0 + 0.333333 * e->m_w1);
2657         formula.update(pOld, p);
2658         pOld = p;
2659         pointAdded++;
2660       } else
2661         for (int j = firstControlPoint; j > lastControlPoint; j -= 2) {
2662           p = s->getControlPoint(j);
2663           formula.update(pOld, p);
2664           pOld = p;
2665           pointAdded++;
2666         }
2667     }
2668     p = s->getPoint(e->m_w1);
2669     formula.update(pOld, p);
2670     pOld = p;
2671     pointAdded++;
2672   }
2673   assert(pointAdded >= 4);
2674 }
2675 
2676 //----------------------------------------------------------------------------------
2677 
2678 static bool isValidArea(const TRegion &r) {
2679   TRegionClockWiseFormula formula;
2680   computeRegionFeature(r, formula);
2681   return formula.isClockwise();
2682 }
2683 
2684 #ifdef LEVO
2685 
2686 bool isValidArea(const vector<TRegion *> &regions, const TRegion &r) {
2687   double area = 0.0;
2688   TPointD p, pOld /*, pAux*/;
2689   int pointAdded = 0;
2690 
2691   int size = r.getEdgeCount();
2692 
2693   if (size == 0) return false;
2694 
2695   // if (size<2)
2696   //  return !isMetaRegion(regions, r);
2697 
2698   int firstControlPoint;
2699   int lastControlPoint;
2700 
2701   TEdge *e = r.getEdge(size - 1);
2702   pOld     = e->m_s->getPoint(e->m_w1);
2703 
2704   for (int i = 0; i < size; i++) {
2705     TEdge *e          = r.getEdge(i);
2706     TStroke *s        = e->m_s;
2707     firstControlPoint = s->getControlPointIndexAfterParameter(e->m_w0);
2708     lastControlPoint  = s->getControlPointIndexAfterParameter(e->m_w1);
2709 
2710     p = s->getPoint(e->m_w0);
2711     area += (p.y + pOld.y) * (pOld.x - p.x);
2712     pOld = p;
2713     pointAdded++;
2714     if (firstControlPoint <= lastControlPoint) {
2715       if (firstControlPoint & 0x1) firstControlPoint++;
2716       if (lastControlPoint - firstControlPoint <=
2717           2)  /// per evitare di avere troppi pochi punti....
2718       {
2719         p = s->getPoint(0.333333 * e->m_w0 + 0.666666 * e->m_w1);
2720         area += (p.y + pOld.y) * (pOld.x - p.x);
2721         pOld = p;
2722         pointAdded++;
2723         p = s->getPoint(0.666666 * e->m_w0 + 0.333333 * e->m_w1);
2724         area += (p.y + pOld.y) * (pOld.x - p.x);
2725         pOld = p;
2726         pointAdded++;
2727       } else
2728         for (int j = firstControlPoint; j < lastControlPoint; j += 2) {
2729           p = s->getControlPoint(j);
2730           area += (p.y + pOld.y) * (pOld.x - p.x);
2731           pOld = p;
2732           pointAdded++;
2733         }
2734     } else {
2735       firstControlPoint--;  // this case, getControlPointIndexBEFOREParameter
2736       lastControlPoint--;
2737       if (firstControlPoint & 0x1) firstControlPoint--;
2738       if (firstControlPoint - lastControlPoint <=
2739           2)  /// per evitare di avere troppi pochi punti....
2740       {
2741         p = s->getPoint(0.333333 * e->m_w0 + 0.666666 * e->m_w1);
2742         area += (p.y + pOld.y) * (pOld.x - p.x);
2743         pOld = p;
2744         pointAdded++;
2745         p = s->getPoint(0.666666 * e->m_w0 + 0.333333 * e->m_w1);
2746         area += (p.y + pOld.y) * (pOld.x - p.x);
2747         pOld = p;
2748         pointAdded++;
2749       } else
2750         for (int j = firstControlPoint; j > lastControlPoint; j -= 2) {
2751           p = s->getControlPoint(j);
2752           area += (p.y + pOld.y) * (pOld.x - p.x);
2753           pOld = p;
2754           pointAdded++;
2755         }
2756     }
2757     p = s->getPoint(e->m_w1);
2758     area += (p.y + pOld.y) * (pOld.x - p.x);
2759     pOld = p;
2760     pointAdded++;
2761   }
2762   assert(pointAdded >= 4);
2763 
2764   return area > 0.5;
2765 }
2766 
2767 #endif
2768 
2769 //-----------------------------------------------------------------------------
2770 
2771 void transferColors(const list<TEdge *> &oldList, const list<TEdge *> &newList,
2772                     bool isStrokeChanged, bool isFlipped, bool overwriteColor);
2773 
2774 //-----------------------------------------------------------------------------
2775 static void printStrokes1(vector<VIStroke *> &v, int size) {
2776   UINT i = 0;
2777   ofstream of("C:\\temp\\strokes.txt");
2778 
2779   for (i = 0; i < (UINT)size; i++) {
2780     TStroke *s = v[i]->m_s;
2781     of << "***stroke " << i << endl;
2782     for (UINT j = 0; j < (UINT)s->getChunkCount(); j++) {
2783       const TThickQuadratic *q = s->getChunk(j);
2784 
2785       of << "   s0 " << q->getP0() << endl;
2786       of << "   s1 " << q->getP1() << endl;
2787       of << "   s2 " << q->getP2() << endl;
2788       of << "****** " << endl;
2789     }
2790     of << endl;
2791   }
2792   for (i = size; i < v.size(); i++) {
2793     TStroke *s = v[i]->m_s;
2794     of << "***Autostroke " << i << endl;
2795     of << "s0 " << s->getPoint(0.0) << endl;
2796     of << "s1 " << s->getPoint(1.0) << endl;
2797     of << endl;
2798   }
2799 }
2800 
2801 //-----------------------------------------------------------------------------
2802 void printStrokes1(vector<VIStroke *> &v, int size);
2803 
2804 // void testHistory();
2805 
2806 // Trova le regioni in una TVectorImage
2807 int TVectorImage::Imp::computeRegions() {
2808 #ifdef NEW_REGION_FILL
2809   return 0;
2810 #endif
2811 
2812 #if defined(_DEBUG) && !defined(MACOSX)
2813   TStopWatch stopWatch;
2814   stopWatch.start(true);
2815 #endif
2816 
2817   // testHistory();
2818 
2819   if (!m_computeRegions) return 0;
2820 
2821   QMutexLocker sl(m_mutex);
2822 
2823   /*if (m_intersectionData->m_computedAlmostOnce)
2824 {
2825 UINT i,n=m_strokes.size();
2826   vector<int> vv(n);
2827 for( i=0; i<n;++i) vv[i] = i;
2828 m_intersectionData->m_computedAlmostOnce = true;
2829 notifyChangedStrokes(vv,vector<TStroke*>(), false);
2830 
2831 return true;
2832 }*/
2833 
2834   // g_autocloseTolerance = m_autocloseTolerance;
2835 
2836   // Cancella le regioni gia' esistenti per ricalcolarle
2837   clearPointerContainer(m_regions);
2838   m_regions.clear();
2839 
2840   // Controlla che ci siano degli stroke
2841   if (m_strokes.empty()) {
2842 #if defined(_DEBUG) && !defined(MACOSX)
2843     stopWatch.stop();
2844 #endif
2845     return 0;
2846   }
2847 
2848   // Inizializza la lista di intersezioni intList
2849   m_computedAlmostOnce          = true;
2850   VIList<Intersection> &intList = m_intersectionData->m_intList;
2851   cleanIntersectionMarks(intList);
2852 
2853   // calcolo struttura delle intersezioni
2854   int added = 0, notAdded = 0;
2855   int strokeSize;
2856   strokeSize = computeIntersections();
2857 
2858   Intersection *p1;
2859   IntersectedStroke *p2;
2860 
2861   for (p1 = intList.first(); p1; p1 = p1->next())
2862     for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next()) p2->m_edge.m_r = 0;
2863 
2864   for (p1 = intList.first(); p1; p1 = p1->next()) {
2865     // Controlla che il punto in questione non sia isolato
2866     if (p1->m_numInter == 0) continue;
2867 
2868     for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next()) {
2869       TRegion *region;
2870 
2871       // se lo stroke non unisce due punti di intersezione
2872       // non lo considero e vado avanti con un altro stroke
2873       if (!p2->m_nextIntersection) continue;
2874 
2875       // Se lo stroke puntato da t2 non e' stato ancora visitato, trova una
2876       // regione
2877       if (!p2->m_visited &&
2878           (region = ::findRegion(intList, p1, p2, m_minimizeEdges))) {
2879         // Se la regione e' valida la aggiunge al vettore delle regioni
2880         if (isValidArea(*region)) {
2881           added++;
2882 
2883           addRegion(region);
2884 
2885           // Lega ogni ramo della regione alla regione di appartenenza
2886           for (UINT i = 0; i < region->getEdgeCount(); i++) {
2887             TEdge *e = region->getEdge(i);
2888             e->m_r   = region;
2889             if (e->m_index >= 0) m_strokes[e->m_index]->addEdge(e);
2890           }
2891         } else  // Se la regione non e' valida viene scartata
2892         {
2893           notAdded++;
2894           delete region;
2895         }
2896       }
2897     }
2898   }
2899 
2900   if (!m_notIntersectingStrokes) {
2901     UINT i;
2902     for (i = 0; i < m_intersectionData->m_intersectedStrokeArray.size(); i++) {
2903       if (!m_strokes[m_intersectionData->m_intersectedStrokeArray[i].m_index]
2904                ->m_edgeList.empty())
2905         transferColors(
2906             m_intersectionData->m_intersectedStrokeArray[i].m_edgeList,
2907             m_strokes[m_intersectionData->m_intersectedStrokeArray[i].m_index]
2908                 ->m_edgeList,
2909             false, false, true);
2910       clearPointerContainer(
2911           m_intersectionData->m_intersectedStrokeArray[i].m_edgeList);
2912       m_intersectionData->m_intersectedStrokeArray[i].m_edgeList.clear();
2913     }
2914     m_intersectionData->m_intersectedStrokeArray.clear();
2915   }
2916 
2917   assert(m_intersectionData->m_intersectedStrokeArray.empty());
2918 
2919   // tolgo i segmenti aggiunti con l'autoclose
2920   vector<VIStroke *>::iterator it = m_strokes.begin();
2921   advance(it, strokeSize);
2922   m_strokes.erase(it, m_strokes.end());
2923 
2924   m_areValidRegions = true;
2925 
2926 #if defined(_DEBUG)
2927   checkRegions(m_regions);
2928 #endif
2929 
2930   return 0;
2931 }
2932 
2933 //-----------------------------------------------------------------------------
2934 //-----------------------------------------------------------------------------
2935 //-----------------------------------------------------------------------------
2936 //-----------------------------------------------------------------------------
2937 //-----------------------------------------------------------------------------
2938 //-----------------------------------------------------------------------------
2939 //-----------------------------------------------------------------------------
2940 //-----------------------------------------------------------------------------
2941 /*
2942 class Branch
2943   {
2944         TEdge m_edge;
2945   bool m_out, m_visited;
2946         Branch *m_next;
2947         Branch *m_nextBranch;
2948         Intersection* m_intersection;
2949 
2950         public:
2951           Branch* next()
2952                   {
2953                         assert(m_intersection);
2954                         return m_next?m_next:m_intersection->m_branchList;
2955                         }
2956         }
2957 
2958 
2959 class Intersection
2960   {
2961         private:
2962         TPointD m_intersectionPoint;
2963   int m_intersectionCount;
2964   Branch *m_branchList;
2965         Intersection* m_next;
2966   list<IntersectedStroke> m_strokeList;
2967         public:
2968   AddIntersection(int index0, int index1, DoublePair intersectionValues);
2969 
2970         }
2971 
2972 */
2973 
2974 #ifdef _DEBUG
2975 
2976 void TVectorImage::Imp::checkRegions(const std::vector<TRegion *> &regions) {
2977   for (UINT i = 0; i < regions.size(); i++) {
2978     TRegion *r = regions[i];
2979     UINT j     = 0;
2980     for (j = 0; j < r->getEdgeCount(); j++) {
2981       TEdge *e = r->getEdge(j);
2982       // assert(areSameGroup(e->m_index, false,
2983       // ==m_strokes[r->getEdge(0)->m_index]->m_groupId);
2984       assert(e->m_r == r);
2985       // if (e->m_s->isSelfLoop())
2986       //  {
2987       //  assert(r->getEdgeCount()==1);
2988       // assert(r->getSubregionCount()==0);
2989       //  }
2990       // if (j>0)
2991       //  assert(!e->m_s->isSelfLoop());
2992     }
2993     if (r->getSubregionCount() > 0) {
2994       std::vector<TRegion *> aux(r->getSubregionCount());
2995       for (j = 0; j < r->getSubregionCount(); j++) aux[j] = r->getSubregion(j);
2996       checkRegions(aux);
2997     }
2998   }
2999 }
3000 
3001 #endif
3002 
3003 namespace {
3004 
3005 inline TGroupId getGroupId(TRegion *r, const std::vector<VIStroke *> &strokes) {
3006   for (UINT i = 0; i < r->getEdgeCount(); i++)
3007     if (r->getEdge(i)->m_index >= 0)
3008       return strokes[r->getEdge(i)->m_index]->m_groupId;
3009   return TGroupId();
3010 }
3011 }
3012 
3013 //------------------------------------------------------------
3014 
3015 TRegion *TVectorImage::findRegion(const TRegion &region) const {
3016   TRegion *ret = 0;
3017 
3018   for (std::vector<TRegion *>::iterator it = m_imp->m_regions.begin();
3019        it != m_imp->m_regions.end(); ++it)
3020     if ((ret = (*it)->findRegion(region)) != 0) return ret;
3021 
3022   return 0;
3023 }
3024 
3025 //------------------------------------------------------------
3026 
3027 void TVectorImage::Imp::addRegion(TRegion *region) {
3028   for (std::vector<TRegion *>::iterator it = m_regions.begin();
3029        it != m_regions.end(); ++it) {
3030     if (getGroupId(region, m_strokes) != getGroupId(*it, m_strokes)) continue;
3031 
3032     if (region->contains(**it)) {
3033       // region->addSubregion(*it);
3034       region->addSubregion(*it);
3035       it = m_regions.erase(it);
3036       while (it != m_regions.end()) {
3037         if (region->contains(**it)) {
3038           region->addSubregion(*it);
3039           // region->addSubregion(*it);
3040           it = m_regions.erase(it);
3041         } else
3042           it++;
3043       }
3044 
3045       m_regions.push_back(region);
3046       return;
3047     } else if ((*it)->contains(*region)) {
3048       (*it)->addSubregion(region);
3049       //(*it)->addSubregion(region);
3050       return;
3051     }
3052   }
3053   m_regions.push_back(region);
3054 }
3055 
3056 //-----------------------------------------------------------------------------
3057 
3058 void TVectorImage::replaceStroke(int index, TStroke *newStroke) {
3059   if ((int)m_imp->m_strokes.size() <= index) return;
3060 
3061   delete m_imp->m_strokes[index]->m_s;
3062   m_imp->m_strokes[index]->m_s = newStroke;
3063 
3064   Intersection *p1;
3065   IntersectedStroke *p2;
3066 
3067   for (p1 = m_imp->m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3068     for (p2 = (*p1).m_strokeList.first(); p2; p2      = p2->next())
3069       if (p2->m_edge.m_index == index) p2->m_edge.m_s = newStroke;
3070 }
3071 
3072 //-----------------------------------------------------------------------------
3073 
3074 //-----------------------------------------------------------------------------
3075 
3076 void TVectorImage::Imp::moveStroke(int fromIndex, int moveBefore) {
3077   assert((int)m_strokes.size() > fromIndex);
3078   assert((int)m_strokes.size() >= moveBefore);
3079 
3080 #ifdef _DEBUG
3081   checkIntersections();
3082 #endif
3083 
3084   VIStroke *vi = m_strokes[fromIndex];
3085 
3086   m_strokes.erase(m_strokes.begin() + fromIndex);
3087 
3088   std::vector<VIStroke *>::iterator it = m_strokes.begin();
3089   if (fromIndex < moveBefore)
3090     advance(it, moveBefore - 1);
3091   else
3092     advance(it, moveBefore);
3093 
3094   m_strokes.insert(it, vi);
3095 
3096   Intersection *p1;
3097   IntersectedStroke *p2;
3098 
3099   for (p1 = m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3100     for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next()) {
3101       if (fromIndex < moveBefore) {
3102         if (p2->m_edge.m_index == fromIndex)
3103           p2->m_edge.m_index = moveBefore - 1;
3104         else if (p2->m_edge.m_index > fromIndex &&
3105                  p2->m_edge.m_index < moveBefore)
3106           p2->m_edge.m_index--;
3107       } else  //(fromIndex>moveBefore)
3108       {
3109         if (p2->m_edge.m_index == fromIndex)
3110           p2->m_edge.m_index = moveBefore;
3111         else if (p2->m_edge.m_index >= moveBefore &&
3112                  p2->m_edge.m_index < fromIndex)
3113           p2->m_edge.m_index++;
3114       }
3115     }
3116 
3117 #ifdef _DEBUG
3118   checkIntersections();
3119 #endif
3120 }
3121 
3122 //-----------------------------------------------------------------------------
3123 
3124 void TVectorImage::Imp::reindexEdges(UINT strokeIndex) {
3125   Intersection *p1;
3126   IntersectedStroke *p2;
3127 
3128   for (p1 = m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3129     for (p2 = (*p1).m_strokeList.first(); p2; p2 = p2->next()) {
3130       assert(p2->m_edge.m_index != (int)strokeIndex || p2->m_edge.m_index < 0);
3131       if (p2->m_edge.m_index > (int)strokeIndex) p2->m_edge.m_index--;
3132     }
3133 }
3134 
3135 //-----------------------------------------------------------------------------
3136 
3137 void TVectorImage::Imp::reindexEdges(const vector<int> &indexes,
3138                                      bool areAdded) {
3139   int i;
3140   int size = indexes.size();
3141 
3142   if (size == 0) return;
3143 
3144 #ifdef _DEBUG
3145   for (i = 0; i < size; i++) assert(i == 0 || indexes[i - 1] < indexes[i]);
3146 #endif
3147 
3148   int min = (int)indexes[0];
3149 
3150   Intersection *p1;
3151   IntersectedStroke *p2;
3152 
3153   for (p1 = m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3154     for (p2 = p1->m_strokeList.first(); p2; p2 = p2->next()) {
3155       if (areAdded) {
3156         if (p2->m_edge.m_index < min)
3157           continue;
3158         else
3159           for (i = size - 1; i >= 0; i--)
3160             if (p2->m_edge.m_index >= (int)indexes[i] - i) {
3161               p2->m_edge.m_index += i + 1;
3162               break;
3163             }
3164       } else {
3165         if (p2->m_edge.m_index < min)
3166           continue;
3167         else
3168           for (i = size - 1; i >= 0; i--)
3169             if (p2->m_edge.m_index > (int)indexes[i]) {
3170               p2->m_edge.m_index -= i + 1;
3171               break;
3172             }
3173       }
3174       // assert(it2->m_edge.m_index!=1369);
3175     }
3176 }
3177 
3178 //-----------------------------------------------------------------------------
3179 
3180 void TVectorImage::Imp::insertStrokeAt(VIStroke *vs, int strokeIndex,
3181                                        bool recomputeRegions) {
3182   list<TEdge *> oldEdgeList, emptyList;
3183 
3184   if (m_computedAlmostOnce && recomputeRegions) {
3185     oldEdgeList = vs->m_edgeList;
3186     vs->m_edgeList.clear();
3187   }
3188 
3189   assert(strokeIndex >= 0 && strokeIndex <= (int)m_strokes.size());
3190 
3191   vector<VIStroke *>::iterator it = m_strokes.begin();
3192   advance(it, strokeIndex);
3193 
3194   vs->m_isNewForFill = true;
3195   m_strokes.insert(it, vs);
3196 
3197   if (!m_computedAlmostOnce) return;
3198 
3199   Intersection *p1;
3200   IntersectedStroke *p2;
3201 
3202   for (p1 = m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3203     for (p2 = (*p1).m_strokeList.first(); p2; p2 = p2->next())
3204       if (p2->m_edge.m_index >= (int)strokeIndex) p2->m_edge.m_index++;
3205 
3206   if (!recomputeRegions) return;
3207 
3208   computeRegions();
3209   transferColors(oldEdgeList, m_strokes[strokeIndex]->m_edgeList, true, false,
3210                  true);
3211 
3212   /*
3213 #ifdef _DEBUG
3214 checkIntersections();
3215 #endif
3216 */
3217 }
3218 
3219 //-----------------------------------------------------------------------------
3220 
3221 void invalidateRegionPropAndBBox(TRegion *reg) {
3222   for (UINT regId = 0; regId != reg->getSubregionCount(); regId++) {
3223     invalidateRegionPropAndBBox(reg->getSubregion(regId));
3224   }
3225   reg->invalidateProp();
3226   reg->invalidateBBox();
3227 }
3228 
3229 void TVectorImage::transform(const TAffine &aff, bool doChangeThickness) {
3230   UINT i;
3231   for (i = 0; i < m_imp->m_strokes.size(); ++i)
3232     m_imp->m_strokes[i]->m_s->transform(aff, doChangeThickness);
3233 
3234   map<int, VIStroke *>::iterator it =
3235       m_imp->m_intersectionData->m_autocloseMap.begin();
3236   for (; it != m_imp->m_intersectionData->m_autocloseMap.end(); ++it)
3237     it->second->m_s->transform(aff, false);
3238 
3239   for (i = 0; i < m_imp->m_regions.size(); ++i)
3240     invalidateRegionPropAndBBox(m_imp->m_regions[i]);
3241 }
3242 
3243 //-----------------------------------------------------------------------------
3244 
3245 #ifdef _DEBUG
3246 #include "tvectorrenderdata.h"
3247 #include "tgl.h"
3248 void TVectorImage::drawAutocloses(const TVectorRenderData &rd) const {
3249   float width;
3250 
3251   glPushMatrix();
3252   tglMultMatrix(rd.m_aff);
3253 
3254   glGetFloatv(GL_LINE_WIDTH, &width);
3255   tglColor(TPixel(0, 255, 0, 255));
3256   glLineWidth(1.5);
3257   glBegin(GL_LINES);
3258 
3259   Intersection *p1;
3260   IntersectedStroke *p2;
3261 
3262   for (p1 = m_imp->m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3263     for (p2 = (*p1).m_strokeList.first(); p2; p2 = p2->next()) {
3264       if (p2->m_edge.m_index < 0 && p2->m_edge.m_w0 == 0.0) {
3265         TStroke *s = p2->m_edge.m_s;
3266         TPointD p0 = s->getPoint(0.0);
3267         TPointD p1 = s->getPoint(1.0);
3268 
3269         glVertex2d(p0.x, p0.y);
3270         glVertex2d(p1.x, p1.y);
3271       }
3272     }
3273   glEnd();
3274   glLineWidth(width);
3275 
3276   glPopMatrix();
3277 }
3278 
3279 #endif
3280 
3281 //-----------------------------------------------------------------------------
3282 
3283 void TVectorImage::reassignStyles(map<int, int> &table) {
3284   UINT i;
3285   UINT strokeCount = getStrokeCount();
3286   // UINT regionCount = getRegionCount();
3287   for (i = 0; i < strokeCount; ++i) {
3288     TStroke *stroke = getStroke(i);
3289     int styleId     = stroke->getStyle();
3290     if (styleId != 0) {
3291       map<int, int>::iterator it = table.find(styleId);
3292       if (it != table.end()) stroke->setStyle(it->second);
3293     }
3294   }
3295 
3296   Intersection *p1;
3297   IntersectedStroke *p2;
3298 
3299   for (p1 = m_imp->m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3300     for (p2 = (*p1).m_strokeList.first(); p2; p2 = p2->next())
3301       if (p2->m_edge.m_styleId != 0) {
3302         map<int, int>::iterator it = table.find(p2->m_edge.m_styleId);
3303         if (it != table.end()) p2->m_edge.m_styleId = it->second;
3304         // assert(it->second<100);
3305       }
3306 }
3307 
3308 //-----------------------------------------------------------------------------
3309 
3310 struct TDeleteMapFunctor {
3311   void operator()(pair<int, VIStroke *> ptr) { delete ptr.second; }
3312 };
3313 
3314 IntersectionData::~IntersectionData() {
3315 	std::for_each(m_autocloseMap.begin(), m_autocloseMap.end(),
3316                 TDeleteMapFunctor());
3317 }
3318 //-----------------------------------------------------------------------------
3319 
3320 #ifdef _DEBUG
3321 void TVectorImage::Imp::checkIntersections() {
3322   // return;
3323   UINT i, j;
3324 
3325   Intersection *p1;
3326   IntersectedStroke *p2;
3327 
3328   for (i = 0, p1 = m_intersectionData->m_intList.first(); p1;
3329        p1 = p1->next(), i++)
3330     for (j = 0, p2 = (*p1).m_strokeList.first(); p2; p2 = p2->next(), j++) {
3331       IntersectedStroke &is = *p2;
3332       assert(is.m_edge.m_styleId >= 0 && is.m_edge.m_styleId <= 1000);
3333       assert(is.m_edge.m_w0 >= 0 && is.m_edge.m_w0 <= 1);
3334       assert(is.m_edge.m_index < (int)m_strokes.size());
3335       if (is.m_edge.m_index >= 0) {
3336         assert(is.m_edge.m_s->getChunkCount() >= 0 &&
3337                is.m_edge.m_s->getChunkCount() <= 10000);
3338         assert(m_strokes[is.m_edge.m_index]->m_s == is.m_edge.m_s);
3339       } else
3340         assert(m_intersectionData->m_autocloseMap[is.m_edge.m_index]);
3341 
3342       if (p2->m_nextIntersection) {
3343         IntersectedStroke *nextStroke = p2->m_nextStroke;
3344         assert(nextStroke->m_nextIntersection == p1);
3345         assert(nextStroke->m_nextStroke == p2);
3346       }
3347     }
3348 
3349   for (i = 0; i < m_strokes.size(); i++) {
3350     VIStroke *vs                       = m_strokes[i];
3351     list<TEdge *>::const_iterator it   = vs->m_edgeList.begin(),
3352                                   it_e = vs->m_edgeList.end();
3353     for (; it != it_e; ++it) {
3354       TEdge *e = *it;
3355       assert(e->getStyle() >= 0 && e->getStyle() <= 1000);
3356       assert(e->m_w0 >= 0 && e->m_w1 <= 1);
3357       assert(e->m_s == vs->m_s);
3358       assert(e->m_s->getChunkCount() >= 0 && e->m_s->getChunkCount() <= 10000);
3359       // assert(e->m_index<(int)m_strokes.size());   l'indice nella stroke
3360       // potrebbe essere non valido, non importa.
3361       // assert(m_strokes[e->m_index]->m_s==e->m_s); deve essere buono nella
3362       // intersectionData
3363     }
3364   }
3365 
3366   for (i = 0; i < m_regions.size(); i++) {
3367     m_regions[i]->checkRegion();
3368   }
3369 }
3370 
3371 #endif
3372 //-----------------------------------------------------------------------------
3373 
3374 TStroke *TVectorImage::Imp::removeEndpoints(int strokeIndex) {
3375 #ifdef _DEBUG
3376   checkIntersections();
3377 #endif
3378 
3379   VIStroke *vs = m_strokes[strokeIndex];
3380 
3381   if (vs->m_s->isSelfLoop()) return 0;
3382   if (vs->m_edgeList.empty()) return 0;
3383 
3384   list<TEdge *>::iterator it = vs->m_edgeList.begin();
3385 
3386   double minW = 1.0;
3387   double maxW = 0.0;
3388   for (; it != vs->m_edgeList.end(); ++it) {
3389     minW = std::min({minW - 0.00002, (*it)->m_w0, (*it)->m_w1});
3390     maxW = std::max({maxW + 0.00002, (*it)->m_w0, (*it)->m_w1});
3391   }
3392 
3393   if (areAlmostEqual(minW, 0.0, 0.001) && areAlmostEqual(maxW, 1.0, 0.001))
3394     return 0;
3395 
3396   TStroke *oldS = vs->m_s;
3397 
3398   TStroke *s = new TStroke(*(vs->m_s));
3399 
3400   double offs = s->getLength(minW);
3401 
3402   TStroke s0, s1, final;
3403 
3404   if (!areAlmostEqual(maxW, 1.0, 0.001)) {
3405     s->split(maxW, s0, s1);
3406   } else
3407     s0 = *s;
3408 
3409   if (!areAlmostEqual(minW, 0.0, 0.001)) {
3410     double newW = (maxW == 1.0) ? minW : s0.getParameterAtLength(offs);
3411     s0.split(newW, s1, final);
3412   } else
3413     final = s0;
3414 
3415   vs->m_s = new TStroke(final);
3416   vs->m_s->setStyle(oldS->getStyle());
3417 
3418   for (it = vs->m_edgeList.begin(); it != vs->m_edgeList.end(); ++it) {
3419     (*it)->m_w0 =
3420         vs->m_s->getParameterAtLength(s->getLength((*it)->m_w0) - offs);
3421     (*it)->m_w1 =
3422         vs->m_s->getParameterAtLength(s->getLength((*it)->m_w1) - offs);
3423     (*it)->m_s = vs->m_s;
3424   }
3425 
3426   Intersection *p1;
3427   IntersectedStroke *p2;
3428 
3429   for (p1 = m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3430     for (p2 = (*p1).m_strokeList.first(); p2; p2 = p2->next()) {
3431       if (p2->m_edge.m_s == oldS) {
3432         p2->m_edge.m_w0 =
3433             vs->m_s->getParameterAtLength(s->getLength(p2->m_edge.m_w0) - offs);
3434         p2->m_edge.m_w1 =
3435             vs->m_s->getParameterAtLength(s->getLength(p2->m_edge.m_w1) - offs);
3436         p2->m_edge.m_s = vs->m_s;
3437       }
3438     }
3439 
3440 #ifdef _DEBUG
3441   checkIntersections();
3442 #endif
3443 
3444   return oldS;
3445 }
3446 
3447 //-----------------------------------------------------------------------------
3448 
3449 void TVectorImage::Imp::restoreEndpoints(int index, TStroke *oldStroke) {
3450 #ifdef _DEBUG
3451   checkIntersections();
3452 #endif
3453 
3454   VIStroke *vs = m_strokes[index];
3455 
3456   TStroke *s = vs->m_s;
3457   TPointD p  = s->getPoint(0.0);
3458 
3459   double offs = oldStroke->getLength(oldStroke->getW(p));
3460 
3461   vs->m_s = oldStroke;
3462 
3463   list<TEdge *>::iterator it = vs->m_edgeList.begin();
3464   for (; it != vs->m_edgeList.end(); ++it) {
3465     (*it)->m_w0 =
3466         vs->m_s->getParameterAtLength(s->getLength((*it)->m_w0) + offs);
3467     (*it)->m_w1 =
3468         vs->m_s->getParameterAtLength(s->getLength((*it)->m_w1) + offs);
3469     (*it)->m_s = vs->m_s;
3470   }
3471 
3472   Intersection *p1;
3473   IntersectedStroke *p2;
3474 
3475   for (p1 = m_intersectionData->m_intList.first(); p1; p1 = p1->next())
3476     for (p2 = (*p1).m_strokeList.first(); p2; p2 = p2->next()) {
3477       if (p2->m_edge.m_s == s) {
3478         p2->m_edge.m_w0 =
3479             vs->m_s->getParameterAtLength(s->getLength(p2->m_edge.m_w0) + offs);
3480         p2->m_edge.m_w1 =
3481             vs->m_s->getParameterAtLength(s->getLength(p2->m_edge.m_w1) + offs);
3482         p2->m_edge.m_s = vs->m_s;
3483       }
3484     }
3485 
3486   delete s;
3487 
3488 #ifdef _DEBUG
3489   checkIntersections();
3490 #endif
3491 }
3492