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 *> ®ions, 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 *> ®ions) {
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 ®ion) 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