1 
2 
3 #include "tcurves.h"
4 //#include "tpalette.h"
5 #include "tvectorimage.h"
6 #include "tvectorimageP.h"
7 #include "tstroke.h"
8 //#include "tgl.h"
9 #include "tvectorrenderdata.h"
10 #include "tmathutil.h"
11 //#include "tdebugmessage.h"
12 #include "tofflinegl.h"
13 //#include "tcolorstyles.h"
14 #include "tpaletteutil.h"
15 #include "tthreadmessage.h"
16 #include "tsimplecolorstyles.h"
17 #include "tcomputeregions.h"
18 
19 #include <memory>
20 
21 //=============================================================================
22 typedef TVectorImage::IntersectionBranch IntersectionBranch;
23 
24 namespace {
25 
26 typedef std::set<int> DisabledStrokeStyles;
27 
28 // uso getDisabledStrokeStyleSet() invece che accedere direttamente alla
29 // variabile per assicurarmi che il tutto funzioni anche quando viene
30 // usato PRIMA del main (per iniziativa di un costruttore di una variabile
31 // globale, p.es.).
32 // per l'idioma: cfr. Modern C++ design, Andrei Alexandrescu, Addison Wesley
33 // 2001, p.133
34 
getDisabledStrokeStyleSet()35 inline DisabledStrokeStyles &getDisabledStrokeStyleSet() {
36   static DisabledStrokeStyles disabledStokeStyles;
37   return disabledStokeStyles;
38 }
39 
isStrokeStyleEnabled__(int index)40 inline bool isStrokeStyleEnabled__(int index) {
41   DisabledStrokeStyles &disabledSet = getDisabledStrokeStyleSet();
42   return disabledSet.find(index) == disabledSet.end();
43 }
44 
45 }  // namespace
46 
47 //=============================================================================
48 
49 /*!
50 Permette di copiare effettuare delle copie delle curve
51 */
52 /*
53 template <class Container>
54 class StrokeArrayInsertIterator
55 {
56   Container& container;
57 
58 public:
59   explicit    StrokeArrayInsertIterator(Container& Line)
60     :container(Line)
61   {};
62 
63   StrokeArrayInsertIterator& operator=(const VIStroke* value )
64   {
65     TStroke *stroke = new TStroke(*(value->m_s));
66 
67     stroke->setId(value->m_s->getId());
68     container.push_back(new VIStroke(stroke));
69     return *this;
70   };
71 
72   StrokeArrayInsertIterator&  operator*()       { return *this; }
73   StrokeArrayInsertIterator&  operator++()       { return *this; }
74   StrokeArrayInsertIterator   operator++(int val){ return *this; }
75 };
76 */
77 
78 //=============================================================================
79 /*!
80 TVectorImage::Imp: implementation of TVectorImage class
81 \relates  TVectorImage
82 */
83 
84 //=============================================================================
85 
Imp(TVectorImage * vi)86 TVectorImage::Imp::Imp(TVectorImage *vi)
87     : m_areValidRegions(false)
88     , m_notIntersectingStrokes(false)
89     , m_computeRegions(true)
90     , m_autocloseTolerance(c_newAutocloseTolerance)
91     , m_maxGroupId(1)
92     , m_maxGhostGroupId(1)
93     , m_mutex(new TThread::Mutex())
94     , m_vi(vi)
95     , m_intersectionData(0)
96     , m_computedAlmostOnce(false)
97     , m_justLoaded(false)
98     , m_insideGroup(TGroupId())
99     , m_minimizeEdges(true)
100 #ifdef NEW_REGION_FILL
101     , m_regionFinder(0)
102 #endif
103 {
104 #ifdef NEW_REGION_FILL
105   resetRegionFinder();
106 #endif
107   initRegionsData();
108 }
109 
~Imp()110 TVectorImage::Imp::~Imp() {
111   // delete m_regionFinder;
112   deleteRegionsData();
113   delete m_mutex;
114 }
115 
116 //=============================================================================
117 
TVectorImage(bool loaded)118 TVectorImage::TVectorImage(bool loaded) : m_imp(new TVectorImage::Imp(this)) {
119   if (loaded) m_imp->m_justLoaded = true;
120 }
121 
122 //-----------------------------------------------------------------------------
123 
~TVectorImage()124 TVectorImage::~TVectorImage() {}
125 
126 //-----------------------------------------------------------------------------
127 
isInsideGroup() const128 int TVectorImage::isInsideGroup() const {
129   return m_imp->m_insideGroup.getDepth();
130 }
131 
132 //-----------------------------------------------------------------------------
133 
addStrokeToGroup(TStroke * stroke,int strokeIndex)134 int TVectorImage::addStrokeToGroup(TStroke *stroke, int strokeIndex) {
135   if (!m_imp->m_strokes[strokeIndex]->m_groupId.isGrouped())
136     return addStroke(stroke, true);
137   for (int i = m_imp->m_strokes.size() - 1; i >= 0; i--)
138     if (m_imp->m_strokes[i]->m_groupId ==
139         m_imp->m_strokes[strokeIndex]->m_groupId) {
140       m_imp->insertStrokeAt(
141           new VIStroke(stroke, m_imp->m_strokes[i]->m_groupId), i + 1);
142       return i + 1;
143     }
144   assert(false);
145   return -1;
146 }
147 
148 //-----------------------------------------------------------------------------
149 
addStroke(TStroke * stroke,bool discardPoints)150 int TVectorImage::addStroke(TStroke *stroke, bool discardPoints) {
151   if (discardPoints) {
152     TRectD bBox = stroke->getBBox();
153     if (bBox.x0 == bBox.x1 && bBox.y0 == bBox.y1)  // empty stroke: discard
154       return -1;
155   }
156 
157   if (m_imp->m_insideGroup != TGroupId()) {
158     int i;
159     for (i = m_imp->m_strokes.size() - 1; i >= 0; i--)
160       if (m_imp->m_insideGroup.isParentOf(m_imp->m_strokes[i]->m_groupId)) {
161         m_imp->insertStrokeAt(
162             new VIStroke(stroke, m_imp->m_strokes[i]->m_groupId), i + 1);
163         return i + 1;
164       }
165   }
166 
167   TGroupId gid;
168   if (m_imp->m_strokes.empty() ||
169       m_imp->m_strokes.back()->m_groupId.isGrouped() != 0)
170     gid = TGroupId(this, true);
171   else
172     gid = m_imp->m_strokes.back()->m_groupId;
173 
174   m_imp->m_strokes.push_back(new VIStroke(stroke, gid));
175   m_imp->m_areValidRegions = false;
176   return m_imp->m_strokes.size() - 1;
177 }
178 
179 //-----------------------------------------------------------------------------
180 
moveStrokes(int fromIndex,int count,int moveBefore)181 void TVectorImage::moveStrokes(int fromIndex, int count, int moveBefore) {
182 #ifdef _DEBUG
183   m_imp->checkGroups();
184 #endif
185   m_imp->moveStrokes(fromIndex, count, moveBefore, true);
186 #ifdef _DEBUG
187   m_imp->checkGroups();
188 #endif
189 }
190 
191 //-----------------------------------------------------------------------------
192 
moveStrokes(int fromIndex,int count,int moveBefore,bool regroup)193 void TVectorImage::Imp::moveStrokes(int fromIndex, int count, int moveBefore,
194                                     bool regroup) {
195   assert(fromIndex >= 0 && fromIndex < (int)m_strokes.size());
196   assert(moveBefore >= 0 && moveBefore <= (int)m_strokes.size());
197   assert(count > 0);
198 
199   assert(fromIndex != moveBefore);
200 
201   for (int i = 0; i < count; i++)
202     if (fromIndex < moveBefore)
203       moveStroke(fromIndex, moveBefore);
204     else
205       moveStroke(fromIndex + i, moveBefore + i);
206 
207   std::vector<int> changedStrokes;
208   if (regroup) regroupGhosts(changedStrokes);
209   if (!changedStrokes.empty())
210     notifyChangedStrokes(changedStrokes, std::vector<TStroke *>(), false);
211 }
212 
213 //-----------------------------------------------------------------------------
214 
insertStrokeAt(VIStroke * vs,int strokeIndex,bool recomputeRegions)215 void TVectorImage::insertStrokeAt(VIStroke *vs, int strokeIndex,
216                                   bool recomputeRegions) {
217   m_imp->insertStrokeAt(vs, strokeIndex, recomputeRegions);
218 }
219 
220 /*
221 void TVectorImage::insertStrokeAt(TStroke *stroke, int strokeIndex, const
222 TGroupId& id)
223 {
224 VIStroke* vs;
225 
226 vs = new VIStroke(stroke, id);
227 
228 m_imp->insertStrokeAt(vs, strokeIndex);
229 
230 }
231 */
232 
233 //-----------------------------------------------------------------------------
234 
235 /*
236 TRectD TVectorImage::addStroke(const std::vector<TThickPoint> &points)
237 {
238 //  era:  TStroke *stroke = makeTStroke(points);
239   TStroke *stroke = TStroke::interpolate(points, 5.0);
240 
241   m_imp->m_strokes.push_back(new VIStroke( stroke) );
242   m_imp->m_areValidRegions = false;
243 
244   return stroke->getBBox();
245 }
246 */
247 
248 //-----------------------------------------------------------------------------
249 
isRegionWithStroke(TRegion * region,TStroke * s)250 static bool isRegionWithStroke(TRegion *region, TStroke *s) {
251   for (UINT i = 0; i < region->getEdgeCount(); i++)
252     if (region->getEdge(i)->m_s == s) return true;
253   return false;
254 }
255 
256 //-----------------------------------------------------------------------------
257 
deleteSubRegionWithStroke(TRegion * region,TStroke * s)258 static void deleteSubRegionWithStroke(TRegion *region, TStroke *s) {
259   for (int i = 0; i < (int)region->getSubregionCount(); i++) {
260     deleteSubRegionWithStroke(region->getSubregion(i), s);
261     if (isRegionWithStroke(region->getSubregion(i), s)) {
262       TRegion *r = region->getSubregion(i);
263       r->moveSubregionsTo(region);
264       assert(r->getSubregionCount() == 0);
265       region->deleteSubregion(i);
266       delete r;
267       i--;
268     }
269   }
270 }
271 
272 //-----------------------------------------------------------------------------
273 
removeStroke(int index,bool doComputeRegions)274 TStroke *TVectorImage::removeStroke(int index, bool doComputeRegions) {
275   return m_imp->removeStroke(index, doComputeRegions);
276 }
277 
removeStroke(int index,bool doComputeRegions)278 TStroke *TVectorImage::Imp::removeStroke(int index, bool doComputeRegions) {
279   assert(index >= 0 && index < (int)m_strokes.size());
280   QMutexLocker sl(m_mutex);
281 
282   VIStroke *stroke = m_strokes[index];
283 
284   eraseIntersection(index);
285 
286   m_strokes.erase(m_strokes.begin() + index);
287 
288   if (m_computedAlmostOnce) {
289     reindexEdges(index);
290     if (doComputeRegions) computeRegions();
291   }
292 
293   return stroke->m_s;
294 }
295 
296 //-----------------------------------------------------------------------------
297 
removeStrokes(const std::vector<int> & toBeRemoved,bool deleteThem,bool recomputeRegions)298 void TVectorImage::removeStrokes(const std::vector<int> &toBeRemoved,
299                                  bool deleteThem, bool recomputeRegions) {
300   m_imp->removeStrokes(toBeRemoved, deleteThem, recomputeRegions);
301 }
302 
303 //-----------------------------------------------------------------------------
304 
removeStrokes(const std::vector<int> & toBeRemoved,bool deleteThem,bool recomputeRegions)305 void TVectorImage::Imp::removeStrokes(const std::vector<int> &toBeRemoved,
306                                       bool deleteThem, bool recomputeRegions) {
307   QMutexLocker sl(m_mutex);
308 
309   for (int i = toBeRemoved.size() - 1; i >= 0; i--) {
310     assert(i == 0 || toBeRemoved[i - 1] < toBeRemoved[i]);
311     UINT index = toBeRemoved[i];
312 
313     eraseIntersection(index);
314     if (deleteThem) delete m_strokes[index];
315     m_strokes.erase(m_strokes.begin() + index);
316   }
317 
318   if (m_computedAlmostOnce && !toBeRemoved.empty()) {
319     reindexEdges(toBeRemoved, false);
320 
321     if (recomputeRegions)
322       computeRegions();
323     else
324       m_areValidRegions = false;
325   }
326 }
327 
328 //-----------------------------------------------------------------------------
329 
deleteStroke(int index)330 void TVectorImage::deleteStroke(int index) {
331   TStroke *stroke = removeStroke(index);
332   delete stroke;
333 }
334 
335 //-----------------------------------------------------------------------------
336 
deleteStroke(VIStroke * stroke)337 void TVectorImage::deleteStroke(VIStroke *stroke) {
338   UINT index = 0;
339   for (; index < m_imp->m_strokes.size(); index++)
340     if (m_imp->m_strokes[index] == stroke) {
341       deleteStroke(index);
342       return;
343     }
344 }
345 
346 //-----------------------------------------------------------------------------
347 
348 /*
349 void TVectorImage::validateRegionEdges(TStroke* stroke, bool invalidate)
350 {
351 if (invalidate)
352   for (UINT i=0; i<getRegionCount(); i++)
353     {
354     TRegion *r = getRegion(i);
355 //  if ((*cit)->getBBox().contains(stroke->getBBox()))
356     for (UINT j=0; j<r->getEdgeCount(); j++)
357       {
358       TEdge* edge = r->getEdge(j);
359       if (edge->m_s == stroke)
360         edge->m_w0 = edge->m_w1 = -1;
361       }
362     }
363 else
364  for (UINT i=0; i<getRegionCount(); i++)
365     {
366     TRegion *r = getRegion(i);
367 //  if ((*cit)->getBBox().contains(stroke->getBBox()))
368     for (UINT j=0; j<r->getEdgeCount(); j++)
369       {
370       TEdge* edge = r->getEdge(j);
371       if (edge->m_w0==-1)
372         {
373         int index;
374         double t, dummy;
375         edge->m_s->getNearestChunk(edge->m_p0, t, index, dummy);
376         edge->m_w0 = getWfromChunkAndT(edge->m_s, index, t);
377         edge->m_s->getNearestChunk(edge->m_p1, t, index, dummy);
378         edge->m_w1 = getWfromChunkAndT(edge->m_s, index, t);
379         }
380       }
381     }
382 
383 
384 }
385 */
386 //-----------------------------------------------------------------------------
387 
getStrokeCount() const388 UINT TVectorImage::getStrokeCount() const { return m_imp->m_strokes.size(); }
389 
390 //-----------------------------------------------------------------------------
391 /*
392 void  TVectorImage::addSeed(const TPointD& p, const TPixel& color)
393 {
394 m_imp->m_seeds.push_back(TFillSeed(color, p, NULL));
395 }
396 */
397 //-----------------------------------------------------------------------------
398 
getRegionCount() const399 UINT TVectorImage::getRegionCount() const {
400   //  assert( m_imp->m_areValidRegions || m_imp->m_regions.empty());
401   return m_imp->m_regions.size();
402 }
403 
404 //-----------------------------------------------------------------------------
405 
getRegion(UINT index) const406 TRegion *TVectorImage::getRegion(UINT index) const {
407   assert(index < m_imp->m_regions.size());
408   //  assert( m_imp->m_areValidRegions );
409   return m_imp->m_regions[index];
410 }
411 
412 //-----------------------------------------------------------------------------
413 
getRegion(TRegionId regId) const414 TRegion *TVectorImage::getRegion(TRegionId regId) const {
415   int index = getStrokeIndexById(regId.m_strokeId);
416 
417   assert(m_imp->m_areValidRegions);
418 
419   TRegion *reg = m_imp->getRegion(regId, index);
420   // assert( reg );
421   return reg;
422 }
423 
424 //-----------------------------------------------------------------------------
425 
getRegion(TRegionId regId,int index) const426 TRegion *TVectorImage::Imp::getRegion(TRegionId regId, int index) const {
427   assert(index != -1);
428   if (index == -1) return 0;
429 
430   assert(index < (int)m_strokes.size());
431   if (index >= (int)m_strokes.size()) return 0;
432 
433   std::list<TEdge *> &edgeList = m_strokes[index]->m_edgeList;
434 
435   std::list<TEdge *>::iterator endList = edgeList.end();
436   double w0;
437   double w1;
438   for (std::list<TEdge *>::iterator it = edgeList.begin(); it != endList;
439        ++it) {
440     w0 = (*it)->m_w0;
441     w1 = (*it)->m_w1;
442 
443     if (w0 < w1) {
444       if (w0 < regId.m_midW && regId.m_midW < w1 && regId.m_direction)
445         return (*it)->m_r;
446     } else {
447       if (w1 < regId.m_midW && regId.m_midW < w0 && !regId.m_direction)
448         return (*it)->m_r;
449     }
450   }
451 
452 #ifdef _DEBUG
453   TPointD cp1 = m_strokes[index]->m_s->getControlPoint(0);
454   TPointD cp2 = m_strokes[index]->m_s->getControlPoint(
455       m_strokes[index]->m_s->getControlPointCount() - 1);
456 #endif
457 
458   return 0;
459 }
460 
461 /*
462 TRegion* TVectorImage::getRegion(TRegionId regId) const
463 {
464   int index = getStrokeIndexById(regId.m_strokeId);
465   assert(index!=-1);
466   if( index == -1 )
467     return 0;
468 
469   assert( index < (int)m_imp->m_strokes.size() );
470   if( index >= (int)m_imp->m_strokes.size() )
471     return 0;
472 
473   std::list<TEdge*> &edgeList = m_imp->m_strokes[index]->m_edgeList;
474 
475   std::list<TEdge*>::iterator endList = edgeList.end();
476   double w0;
477   double w1;
478   for(list<TEdge*>::iterator it= edgeList.begin(); it!=endList; ++it)
479   {
480     w0 = (*it)->m_w0;
481     w1 = (*it)->m_w1;
482 
483     if(w0<w1)
484     {
485       if( w0 < regId.m_midW && regId.m_midW < w1 && regId.m_direction )
486         return (*it)->m_r;
487     }
488     else
489     {
490       if( w1 < regId.m_midW && regId.m_midW < w0 && !regId.m_direction )
491         return (*it)->m_r;
492     }
493   }
494 
495   return 0;
496 }
497 */
498 //-----------------------------------------------------------------------------
499 
setEdgeColors(int strokeIndex,int leftColorIndex,int rightColorIndex)500 void TVectorImage::setEdgeColors(int strokeIndex, int leftColorIndex,
501                                  int rightColorIndex) {
502   std::list<TEdge *> &ll = m_imp->m_strokes[strokeIndex]->m_edgeList;
503 
504   std::list<TEdge *>::const_iterator l   = ll.begin();
505   std::list<TEdge *>::const_iterator l_e = ll.end();
506   for (; l != l_e; ++l) {
507     // double w0 = (*l)->m_w0, w1 = (*l)->m_w1;
508     if ((*l)->m_w0 > (*l)->m_w1) {
509       if (leftColorIndex != -1)
510         (*l)->m_styleId = leftColorIndex;
511       else if (rightColorIndex != -1)
512         (*l)->m_styleId = rightColorIndex;
513     } else {
514       if (rightColorIndex != -1)
515         (*l)->m_styleId = rightColorIndex;
516       else if (leftColorIndex != -1)
517         (*l)->m_styleId = leftColorIndex;
518     }
519   }
520 }
521 
522 //-----------------------------------------------------------------------------
523 
getStroke(UINT index) const524 TStroke *TVectorImage::getStroke(UINT index) const {
525   assert(index < m_imp->m_strokes.size());
526   return m_imp->m_strokes[index]->m_s;
527 }
528 
getVIStroke(UINT index) const529 VIStroke *TVectorImage::getVIStroke(UINT index) const {
530   assert(index < m_imp->m_strokes.size());
531   return m_imp->m_strokes[index];
532 }
533 
534 //-----------------------------------------------------------------------------
535 
getStrokeById(int id) const536 VIStroke *TVectorImage::getStrokeById(int id) const {
537   int n = m_imp->m_strokes.size();
538   for (int i = 0; i < n; i++)
539     if (m_imp->m_strokes[i]->m_s->getId() == id) return m_imp->m_strokes[i];
540   return 0;
541 }
542 
543 //-----------------------------------------------------------------------------
544 
getStrokeIndexById(int id) const545 int TVectorImage::getStrokeIndexById(int id) const {
546   int n = m_imp->m_strokes.size();
547 
548   for (int i = 0; i < n; i++)
549     if (m_imp->m_strokes[i]->m_s->getId() == id) return i;
550 
551   return -1;
552 }
553 
554 //-----------------------------------------------------------------------------
555 
getStrokeIndex(TStroke * stroke) const556 int TVectorImage::getStrokeIndex(TStroke *stroke) const {
557   int n = m_imp->m_strokes.size();
558 
559   for (int i = 0; i < n; i++)
560     if (m_imp->m_strokes[i]->m_s == stroke) return i;
561 
562   return -1;
563 }
564 
565 //-----------------------------------------------------------------------------
566 
getBBox() const567 TRectD TVectorImage::getBBox() const {
568   UINT strokeCount = m_imp->m_strokes.size();
569   if (strokeCount == 0) return TRectD();
570 
571   TPalette *plt = getPalette();
572   TRectD bbox;
573 
574   for (UINT i = 0; i < strokeCount; ++i) {
575     TRectD r           = m_imp->m_strokes[i]->m_s->getBBox();
576     TColorStyle *style = 0;
577     if (plt) style = plt->getStyle(m_imp->m_strokes[i]->m_s->getStyle());
578     if (dynamic_cast<TRasterImagePatternStrokeStyle *>(style) ||
579         dynamic_cast<TVectorImagePatternStrokeStyle *>(
580             style))  // con i pattern style, il render a volte taglia sulla bbox
581                      // dello stroke....
582       // aumento la bbox della meta' delle sue dimensioni:pezzaccia.
583       r = r.enlarge(std::max(r.getLx() * 0.25, r.getLy() * 0.25));
584     bbox = ((i == 0) ? r : bbox + r);
585   }
586 
587   return bbox;
588 }
589 
590 //-----------------------------------------------------------------------------
591 
getNearestStroke(const TPointD & p,double & outW,UINT & strokeIndex,double & dist2,bool onlyInCurrentGroup) const592 bool TVectorImage::getNearestStroke(const TPointD &p, double &outW,
593                                     UINT &strokeIndex, double &dist2,
594                                     bool onlyInCurrentGroup) const {
595   dist2       = (std::numeric_limits<double>::max)();
596   strokeIndex = getStrokeCount();
597   outW        = -1;
598 
599   double tempdis2, tempPar;
600 
601   for (int i = 0; i < (int)m_imp->m_strokes.size(); ++i) {
602     if (onlyInCurrentGroup && !inCurrentGroup(i)) continue;
603     TStroke *s = m_imp->m_strokes[i]->m_s;
604     tempPar    = s->getW(p);
605 
606     tempdis2 = tdistance2(TThickPoint(p, 0), s->getThickPoint(tempPar));
607 
608     if (tempdis2 < dist2) {
609       outW        = tempPar;
610       dist2       = tempdis2;
611       strokeIndex = i;
612     }
613   }
614 
615   return dist2 < (std::numeric_limits<double>::max)();
616 }
617 
618 //-----------------------------------------------------------------------------
619 
620 #if defined(LINUX) || defined(FREEBSD) || defined(MACOSX)
render(const TVectorRenderData & rd,TRaster32P & ras)621 void TVectorImage::render(const TVectorRenderData &rd, TRaster32P &ras) {
622   // hardRenderVectorImage(rd,ras,this);
623 }
624 #endif
625 
626 //-----------------------------------------------------------------------------
627 //#include "timage_io.h"
628 
render(bool onlyStrokes)629 TRaster32P TVectorImage::render(bool onlyStrokes) {
630   TRect bBox = convert(getBBox());
631   if (bBox.isEmpty()) return (TRaster32P)0;
632 
633   std::unique_ptr<TOfflineGL> offlineGlContext(new TOfflineGL(bBox.getSize()));
634   offlineGlContext->clear(TPixel32(0, 0, 0, 0));
635   offlineGlContext->makeCurrent();
636   TVectorRenderData rd(TTranslation(-convert(bBox.getP00())),
637                        TRect(bBox.getSize()), getPalette(), 0, true, true);
638   rd.m_drawRegions = !onlyStrokes;
639   offlineGlContext->draw(this, rd, false);
640 
641   return offlineGlContext->getRaster()->clone();
642 
643   // hardRenderVectorImage(rd,ras,this);
644 }
645 
646 //-----------------------------------------------------------------------------
647 
getRegion(const TPointD & p)648 TRegion *TVectorImage::getRegion(const TPointD &p) {
649 #ifndef NEW_REGION_FILL
650   if (!isComputedRegionAlmostOnce()) return 0;
651 
652   if (!m_imp->m_areValidRegions) m_imp->computeRegions();
653 #endif
654 
655   return m_imp->getRegion(p);
656 }
657 
658 //-----------------------------------------------------------------------------
659 
getRegion(const TPointD & p)660 TRegion *TVectorImage::Imp::getRegion(const TPointD &p) {
661   int strokeIndex = (int)m_strokes.size() - 1;
662 
663   while (strokeIndex >= 0) {
664     for (UINT regionIndex = 0; regionIndex < m_regions.size(); regionIndex++)
665       if (areDifferentGroup(strokeIndex, false, regionIndex, true) == -1 &&
666           m_regions[regionIndex]->contains(p))
667         return m_regions[regionIndex]->getRegion(p);
668     int curr = strokeIndex;
669     while (strokeIndex >= 0 &&
670            areDifferentGroup(curr, false, strokeIndex, false) == -1)
671       strokeIndex--;
672   }
673 
674   return 0;
675 }
676 
677 //-----------------------------------------------------------------------------
678 
fillStrokes(const TPointD & p,int styleId)679 int TVectorImage::fillStrokes(const TPointD &p, int styleId) {
680   UINT index;
681   double outW, dist2;
682 
683   if (getNearestStroke(p, outW, index, dist2, true)) {
684     double thick = getStroke(index)->getThickPoint(outW).thick * 1.25;
685     if (thick < 0.5) thick = 0.5;
686 
687     if (dist2 > thick * thick) return -1;
688     assert(index >= 0 && index < m_imp->m_strokes.size());
689     int ret = m_imp->m_strokes[index]->m_s->getStyle();
690     m_imp->m_strokes[index]->m_s->setStyle(styleId);
691     return ret;
692   }
693 
694   return -1;
695 }
696 
697 //-----------------------------------------------------------------------------
698 
699 #ifdef NEW_REGION_FILL
700 
resetRegionFinder()701 void TVectorImage::resetRegionFinder() { m_imp->resetRegionFinder(); }
702 #else
703 //------------------------------------------------------------------
704 
fill(const TPointD & p,int newStyleId,bool onlyEmpty)705 int TVectorImage::fill(const TPointD &p, int newStyleId, bool onlyEmpty) {
706   TRegion *r = getRegion(p);
707   if (onlyEmpty && r && r->getStyle() != 0) return -1;
708 
709   if (!m_imp->m_areValidRegions) m_imp->computeRegions();
710   return m_imp->fill(p, newStyleId);
711 }
712 #endif
713 
714 //-----------------------------------------------------------------------------
715 /*
716 void TVectorImage::autoFill(int styleId)
717 {
718 m_imp->autoFill(styleId, true);
719 }
720 
721 void TVectorImage::Imp::autoFill(int styleId, bool oddLevel)
722 {
723 if (!m_areValidRegions)
724   computeRegions();
725 for (UINT i = 0; i<m_regions.size(); i++)
726   {
727   if (oddLevel)
728     m_regions[i]->setStyle(styleId);
729   m_regions[i]->autoFill(styleId, !oddLevel);
730   }
731 }
732 */
733 //-----------------------------------------------------------------------------
734 /*
735 void TRegion::autoFill(int styleId, bool oddLevel)
736 {
737 for (UINT i = 0; i<getSubregionCount(); i++)
738   {
739   TRegion* r = getSubregion(i);
740   if (oddLevel)
741     r->setStyle(styleId);
742   r->autoFill(styleId, !oddLevel);
743   }
744 
745 }
746 */
747 //-----------------------------------------------------------------------------
748 
fill(const TPointD & p,int styleId)749 int TVectorImage::Imp::fill(const TPointD &p, int styleId) {
750   int strokeIndex = (int)m_strokes.size() - 1;
751 
752   while (strokeIndex >= 0) {
753     if (!inCurrentGroup(strokeIndex)) {
754       strokeIndex--;
755       continue;
756     }
757     for (UINT regionIndex = 0; regionIndex < m_regions.size(); regionIndex++)
758       if (areDifferentGroup(strokeIndex, false, regionIndex, true) == -1 &&
759           m_regions[regionIndex]->contains(p))
760         return m_regions[regionIndex]->fill(p, styleId);
761     int curr = strokeIndex;
762     while (strokeIndex >= 0 &&
763            areDifferentGroup(curr, false, strokeIndex, false) == -1)
764       strokeIndex--;
765   }
766 
767   return -1;
768 }
769 
770 //-----------------------------------------------------------------------------
771 
selectFill(const TRectD & selArea,TStroke * s,int newStyleId,bool onlyUnfilled,bool fillAreas,bool fillLines)772 bool TVectorImage::selectFill(const TRectD &selArea, TStroke *s, int newStyleId,
773                               bool onlyUnfilled, bool fillAreas,
774                               bool fillLines) {
775   if (!m_imp->m_areValidRegions) m_imp->computeRegions();
776   return m_imp->selectFill(selArea, s, newStyleId, onlyUnfilled, fillAreas,
777                            fillLines);
778 }
779 
780 //-----------------------------------------------------------------------------
781 
selectFill(const TRectD & selArea,TStroke * s,int newStyleId,bool onlyUnfilled,bool fillAreas,bool fillLines)782 bool TVectorImage::Imp::selectFill(const TRectD &selArea, TStroke *s,
783                                    int newStyleId, bool onlyUnfilled,
784                                    bool fillAreas, bool fillLines) {
785   bool hitSome = false;
786 
787   if (s) {
788     TVectorImage aux;
789     aux.addStroke(s);
790     aux.findRegions();
791     for (UINT j = 0; j < aux.getRegionCount(); j++) {
792       TRegion *r0 = aux.getRegion(j);
793       if (fillAreas)
794         for (UINT i = 0; i < m_regions.size(); i++) {
795           TRegion *r1 = m_regions[i];
796 
797           if (m_insideGroup != TGroupId() &&
798               !m_insideGroup.isParentOf(
799                   m_strokes[r1->getEdge(0)->m_index]->m_groupId))
800             continue;
801 
802           if ((!onlyUnfilled || r1->getStyle() == 0) && r0->contains(*r1)) {
803             r1->setStyle(newStyleId);
804             hitSome = true;
805           }
806         }
807       if (fillLines)
808         for (UINT i = 0; i < m_strokes.size(); i++) {
809           if (!inCurrentGroup(i)) continue;
810 
811           TStroke *s1 = m_strokes[i]->m_s;
812           if ((!onlyUnfilled || s1->getStyle() == 0) && r0->contains(*s1)) {
813             s1->setStyle(newStyleId);
814             hitSome = true;
815           }
816         }
817     }
818     aux.removeStroke(0);
819     return hitSome;
820   }
821 
822   // rect fill
823 
824   if (fillAreas)
825 #ifndef NEW_REGION_FILL
826     for (UINT i = 0; i < m_regions.size(); i++) {
827       int index, j = 0;
828 
829       do
830         index = m_regions[i]->getEdge(j++)->m_index;
831       while (index < 0 && j < (int)m_regions[i]->getEdgeCount());
832       // if index<0, means that the region is purely of autoclose strokes!
833       if (m_insideGroup != TGroupId() && index >= 0 &&
834           !m_insideGroup.isParentOf(m_strokes[index]->m_groupId))
835         continue;
836       if (!onlyUnfilled || m_regions[i]->getStyle() == 0)
837         hitSome |= m_regions[i]->selectFill(selArea, newStyleId);
838     }
839 #else
840 
841     findRegions(selArea);
842 
843   for (UINT i = 0; i < m_regions.size(); i++) {
844     if (m_insideGroup != TGroupId() &&
845         !m_insideGroup.isParentOf(
846             m_strokes[m_regions[i]->getEdge(0)->m_index]->m_groupId))
847       continue;
848     if (!onlyUnfilled || m_regions[i]->getStyle() == 0)
849       hitSome |= m_regions[i]->selectFill(selArea, newStyleId);
850   }
851 #endif
852 
853   if (fillLines)
854     for (UINT i = 0; i < m_strokes.size(); i++) {
855       if (!inCurrentGroup(i)) continue;
856 
857       TStroke *s = m_strokes[i]->m_s;
858 
859       if ((!onlyUnfilled || s->getStyle() == 0) &&
860           selArea.contains(s->getBBox())) {
861         s->setStyle(newStyleId);
862         hitSome = true;
863       }
864     }
865   return hitSome;
866 }
867 
868 //-----------------------------------------------------------------------------
869 
870 /*
871 void  TVectorImageImp::seedFill()
872 {
873   std::vector<TFillSeed>::iterator it;
874   TRegion*r;
875 
876   TFillStyleP app =NULL;
877 
878   for (it=m_seeds.begin(); it!=m_seeds.end(); )
879     if ((r=fill(it->m_p, new TColorStyle(it->m_fillStyle.getPointer()) ))!=NULL)
880     {
881       it->m_r = r;
882       it = m_seeds.erase(it);  // i seed provengono da immagini vecchie. non
883 servono piu'.
884     }
885   m_areValidRegions=true;
886 }
887 */
888 //-----------------------------------------------------------------------------
889 /*
890 void  TVectorImage::seedFill()
891 {
892   m_imp->seedFill();
893 
894 }
895 */
896 //-----------------------------------------------------------------------------
897 
notifyChangedStrokes(const std::vector<int> & strokeIndexArray,const std::vector<TStroke * > & oldStrokeArray,bool areFlipped)898 void TVectorImage::notifyChangedStrokes(
899     const std::vector<int> &strokeIndexArray,
900     const std::vector<TStroke *> &oldStrokeArray, bool areFlipped) {
901   std::vector<TStroke *> aux;
902 
903   /*
904 if (oldStrokeArray.empty())
905 {
906   for (int i=0; i<(int)strokeIndexArray.size(); i++)
907     {
908           TStroke *s = getStroke(strokeIndexArray[i]);
909     aux.push_back(s);
910           }
911 m_imp->notifyChangedStrokes(strokeIndexArray, aux, areFlipped);
912   }
913 else*/
914   m_imp->notifyChangedStrokes(strokeIndexArray, oldStrokeArray, areFlipped);
915 }
916 
917 //-----------------------------------------------------------------------------
918 
notifyChangedStrokes(int strokeIndexArray,TStroke * oldStroke,bool isFlipped)919 void TVectorImage::notifyChangedStrokes(int strokeIndexArray,
920                                         TStroke *oldStroke, bool isFlipped) {
921   std::vector<int> app(1);
922   app[0] = strokeIndexArray;
923 
924   std::vector<TStroke *> oldStrokeArray(1);
925   oldStrokeArray[0] = oldStroke ? oldStroke : getStroke(strokeIndexArray);
926   m_imp->notifyChangedStrokes(app, oldStrokeArray, isFlipped);
927 }
928 
929 //-----------------------------------------------------------------------------
930 
931 // ofstream of("C:\\temp\\butta.txt");
932 
transferColors(const std::list<TEdge * > & oldList,const std::list<TEdge * > & newList,bool isStrokeChanged,bool isFlipped,bool overwriteColor)933 void transferColors(const std::list<TEdge *> &oldList,
934                     const std::list<TEdge *> &newList, bool isStrokeChanged,
935                     bool isFlipped, bool overwriteColor) {
936   if (newList.empty() || oldList.empty()) return;
937 
938   std::list<TEdge *>::const_iterator it;
939 // unused variable
940 #if 0
941 list<TEdge*>::const_iterator it1;
942 #endif
943   double totLength;
944   if (isStrokeChanged) totLength = newList.front()->m_s->getLength();
945   for (it = newList.begin(); it != newList.end(); ++it) {
946     int newStyle = -1;  // ErrorStyle;
947 // unused variable
948 #if 0
949   int styleId = (*it)->m_styleId;
950 #endif
951     if (!overwriteColor && (*it)->m_styleId != 0) continue;
952     bool reversed;
953     double deltaMax = 0.005;
954     double l0, l1;
955     if ((*it)->m_w0 > (*it)->m_w1) {
956       reversed = !isFlipped;
957       if (isStrokeChanged) {
958         l0 = (*it)->m_s->getLength((*it)->m_w1) / totLength;
959         l1 = (*it)->m_s->getLength((*it)->m_w0) / totLength;
960       } else {
961         l0 = (*it)->m_w1;
962         l1 = (*it)->m_w0;
963       }
964     } else {
965       reversed = isFlipped;
966       if (isStrokeChanged) {
967         l0 = (*it)->m_s->getLength((*it)->m_w0) / totLength;
968         l1 = (*it)->m_s->getLength((*it)->m_w1) / totLength;
969       } else {
970         l0 = (*it)->m_w0;
971         l1 = (*it)->m_w1;
972       }
973       // w0 = (*it)->m_w0;
974       // w1 = (*it)->m_w1;
975     }
976 
977     std::list<TEdge *>::const_iterator it1 = oldList.begin();
978     for (; it1 != oldList.end(); ++it1) {
979 // unused variable
980 #if 0
981       TEdge*e = *it1;
982 #endif
983       if (/*(*it1)->m_styleId==0 ||*/
984           (reversed && (*it1)->m_w0 < (*it1)->m_w1) ||
985           (!reversed && (*it1)->m_w0 > (*it1)->m_w1))
986         continue;
987       double _l0, _l1;
988       if (isStrokeChanged) {
989         double totLength1 = (*it1)->m_s->getLength();
990 
991         _l0 = (*it1)->m_s->getLength(std::min((*it1)->m_w0, (*it1)->m_w1)) /
992               totLength1;
993         _l1 = (*it1)->m_s->getLength(std::max((*it1)->m_w0, (*it1)->m_w1)) /
994               totLength1;
995       } else {
996         _l0 = std::min((*it1)->m_w0, (*it1)->m_w1);
997         _l1 = std::max((*it1)->m_w0, (*it1)->m_w1);
998       }
999       double delta = std::min(l1, _l1) - std::max(l0, _l0);
1000       if (delta > deltaMax) {
1001         deltaMax = delta;
1002         newStyle = (*it1)->m_styleId;
1003       }
1004     }
1005     if (newStyle >= 0)  // !=ErrorStyle)
1006     {
1007       if ((*it)->m_r)
1008         (*it)->m_r->setStyle(newStyle);
1009       else
1010         (*it)->m_styleId = newStyle;
1011     }
1012   }
1013 }
1014 
1015 //-----------------------------------------------------------------------------
1016 
transferStrokeColors(TVectorImageP sourceImage,int sourceStroke,TVectorImageP destinationImage,int destinationStroke)1017 void TVectorImage::transferStrokeColors(TVectorImageP sourceImage,
1018                                         int sourceStroke,
1019                                         TVectorImageP destinationImage,
1020                                         int destinationStroke) {
1021   std::list<TEdge *> *sourceList =
1022       &(sourceImage->m_imp->m_strokes[sourceStroke]->m_edgeList);
1023   std::list<TEdge *> *destinationList =
1024       &(destinationImage->m_imp->m_strokes[destinationStroke]->m_edgeList);
1025   transferColors(*sourceList, *destinationList, true, false, false);
1026 }
1027 
1028 //-----------------------------------------------------------------------------
1029 
areWholeGroups(const std::vector<int> & indexes) const1030 bool TVectorImage::Imp::areWholeGroups(const std::vector<int> &indexes) const {
1031   UINT i, j;
1032   for (i = 0; i < indexes.size(); i++) {
1033     if (m_strokes[indexes[i]]->m_isNewForFill) return false;
1034     if (!m_strokes[indexes[i]]->m_groupId.isGrouped()) return false;
1035     for (j = 0; j < m_strokes.size(); j++) {
1036       int ret = areDifferentGroup(indexes[i], false, j, false);
1037       if (ret == -1 || (ret >= 1 && find(indexes.begin(), indexes.end(), j) ==
1038                                         indexes.end()))
1039         return false;
1040     }
1041   }
1042   return true;
1043 }
1044 
1045 //-----------------------------------------------------------------------------
1046 
1047 //-------------------------------------------------------------------
1048 
notifyChangedStrokes(const std::vector<int> & strokeIndexArray,const std::vector<TStroke * > & oldStrokeArray,bool areFlipped)1049 void TVectorImage::Imp::notifyChangedStrokes(
1050     const std::vector<int> &strokeIndexArray,
1051     const std::vector<TStroke *> &oldStrokeArray, bool areFlipped) {
1052 #ifdef _DEBUG
1053   checkIntersections();
1054 #endif
1055 
1056   assert(oldStrokeArray.empty() ||
1057          strokeIndexArray.size() == oldStrokeArray.size());
1058 
1059   if (!m_computedAlmostOnce && !m_notIntersectingStrokes) return;
1060 
1061   typedef std::list<TEdge *> EdgeList;
1062   std::vector<EdgeList> oldEdgeListArray(strokeIndexArray.size());
1063   int i;
1064 
1065   // se si sono trasformati  interi gruppi (senza deformare le stroke) non c'e'
1066   // bisogno di ricalcolare le regioni!
1067   if (oldStrokeArray.empty() && areWholeGroups(strokeIndexArray)) {
1068     m_areValidRegions = true;
1069     for (i = 0; i < (int)m_regions.size(); i++)
1070       invalidateRegionPropAndBBox(m_regions[i]);
1071     return;
1072   }
1073 
1074   QMutexLocker sl(m_mutex);
1075   for (i = 0; i < (int)strokeIndexArray.size(); i++)  // ATTENZIONE! non si puo'
1076                                                       // fare eraseIntersection
1077                                                       // in questo stesso ciclo
1078   {
1079     VIStroke *s = m_strokes[strokeIndexArray[i]];
1080     // if (s->m_s->isSelfLoop())
1081     //  assert(s->m_edgeList.size()<=1);
1082 
1083     std::list<TEdge *>::iterator it = s->m_edgeList.begin();
1084     for (; it != s->m_edgeList.end(); it++) {
1085       TEdge *e = new TEdge(**it, false);
1086       if (!oldStrokeArray.empty()) e->m_s = oldStrokeArray[i];
1087       oldEdgeListArray[i].push_back(e);  // bisogna allocare nuovo edge,
1088                                          // perche'la eraseIntersection poi lo
1089                                          // cancella....
1090       if ((*it)->m_toBeDeleted) delete *it;
1091     }
1092     s->m_edgeList.clear();
1093   }
1094 
1095   for (i = 0; i < (int)strokeIndexArray.size(); i++) {
1096     eraseIntersection(strokeIndexArray[i]);
1097     if (!m_notIntersectingStrokes)
1098       m_strokes[strokeIndexArray[i]]->m_isNewForFill = true;
1099   }
1100 
1101   computeRegions();  // m_imp->m_strokes, m_imp->m_regions);
1102 
1103   for (i = 0; i < (int)strokeIndexArray.size(); i++) {
1104     transferColors(oldEdgeListArray[i],
1105                    m_strokes[strokeIndexArray[i]]->m_edgeList, true, areFlipped,
1106                    false);
1107     clearPointerContainer(oldEdgeListArray[i]);
1108   }
1109 
1110 #ifdef _DEBUG
1111   checkIntersections();
1112 #endif
1113 }
1114 
1115 //-----------------------------------------------------------------------------
1116 
findRegions()1117 void TVectorImage::findRegions() {
1118   // for (int i=0; i<(int)m_imp->m_strokes.size(); i++)
1119   //  {
1120   //  m_imp->eraseIntersection(i);
1121   //	  m_imp->m_strokes[i]->m_isNewForFill=true;
1122   //  }
1123 
1124   if (m_imp->m_areValidRegions) return;
1125 
1126   // m_imp->m_regions.clear();
1127 
1128   // compute regions...
1129   m_imp->computeRegions();  // m_imp->m_strokes, m_imp->m_regions);
1130 }
1131 
1132 //-----------------------------------------------------------------------------
1133 
putRegion(TRegion * region)1134 void TVectorImage::putRegion(TRegion *region) {
1135   m_imp->m_regions.push_back(region);
1136 }
1137 
1138 //-----------------------------------------------------------------------------
1139 
1140 //-------------------------------------------------------------------
1141 
cloneRegions(TVectorImage::Imp & out,bool doComputeRegions)1142 void TVectorImage::Imp::cloneRegions(TVectorImage::Imp &out,
1143                                      bool doComputeRegions) {
1144   std::unique_ptr<IntersectionBranch[]> v;
1145   UINT size = getFillData(v);
1146   out.setFillData(v, size, doComputeRegions);
1147 }
1148 
1149 //-----------------------------------------------------------------------------
1150 
clone() const1151 TVectorImageP TVectorImage::clone() const {
1152   return TVectorImageP(cloneImage());
1153 }
1154 
1155 //-----------------------------------------------------------------------------
1156 
cloneImage() const1157 TImage *TVectorImage::cloneImage() const {
1158   TVectorImage *out = new TVectorImage;
1159 
1160   out->m_imp->m_autocloseTolerance = m_imp->m_autocloseTolerance;
1161   out->m_imp->m_maxGroupId         = m_imp->m_maxGroupId;
1162   out->m_imp->m_maxGhostGroupId    = m_imp->m_maxGhostGroupId;
1163 
1164   for (int i = 0; i < (int)m_imp->m_strokes.size(); i++) {
1165     out->m_imp->m_strokes.push_back(new VIStroke(*(m_imp->m_strokes[i])));
1166     out->m_imp->m_strokes.back()->m_s->setId(m_imp->m_strokes[i]->m_s->getId());
1167   }
1168 
1169   m_imp->cloneRegions(*out->m_imp);
1170 
1171   out->setPalette(getPalette());
1172   out->m_imp->m_computedAlmostOnce = m_imp->m_computedAlmostOnce;
1173   out->m_imp->m_justLoaded         = m_imp->m_justLoaded;
1174 
1175   return out;
1176 }
1177 
1178 //-----------------------------------------------------------------------------
1179 /*
1180 TVectorImageP mergeAndClear(TVectorImageP v1, TVectorImageP v2 )
1181 {
1182   TVectorImageP out = new TVectorImage;
1183 
1184   std::vector<VIStroke*>::iterator it_b =  v1->m_imp->m_strokes.begin();
1185   std::vector<VIStroke*>::iterator it_e =  v1->m_imp->m_strokes.end();
1186 
1187   std::copy( it_b, it_e, std::back_inserter( out->m_imp->m_strokes ) );
1188 
1189   it_b =  v2->m_imp->m_strokes.begin();
1190   it_e =  v2->m_imp->m_strokes.end();
1191 
1192   std::copy( it_b, it_e, std::back_inserter( out->m_imp->m_strokes ) );
1193 
1194   v1->m_imp->m_regions.clear();
1195   v1->m_imp->m_strokes.clear();
1196   v2->m_imp->m_regions.clear();
1197   v2->m_imp->m_strokes.clear();
1198 
1199   out->m_imp->m_areValidRegions = false;
1200   return out;
1201 }
1202 */
1203 
1204 //-----------------------------------------------------------------------------
1205 
VIStroke(const VIStroke & s,bool sameId)1206 VIStroke::VIStroke(const VIStroke &s, bool sameId)
1207     : m_isPoint(s.m_isPoint)
1208     , m_isNewForFill(s.m_isNewForFill)
1209     , m_groupId(s.m_groupId) {
1210   m_s                                     = new TStroke(*s.m_s);
1211   std::list<TEdge *>::const_iterator it   = s.m_edgeList.begin(),
1212                                      it_e = s.m_edgeList.end();
1213   for (; it != it_e; ++it) {
1214     m_edgeList.push_back(new TEdge(**it, true));
1215     m_edgeList.back()->m_s = m_s;
1216   }
1217   if (sameId) m_s->setId(s.m_s->getId());
1218 }
1219 
1220 //-----------------------------------------------------------------------------
1221 
mergeImage(const TVectorImageP & img,const TAffine & affine,bool sameStrokeId)1222 int TVectorImage::mergeImage(const TVectorImageP &img, const TAffine &affine,
1223                              bool sameStrokeId) {
1224   QMutexLocker sl(m_imp->m_mutex);
1225 
1226 #ifdef _DEBUG
1227   checkIntersections();
1228 #endif
1229 
1230   TPalette *tarPlt = getPalette();
1231   TPalette *srcPlt = img->getPalette();
1232 
1233   assert(tarPlt);
1234   assert(tarPlt->getPageCount() > 0);
1235 
1236   // merge della palette
1237   std::map<int, int> styleTable;
1238   std::set<int> usedStyles;
1239   img->getUsedStyles(usedStyles);
1240 
1241   // gmt, 16/10/07. Quando si copia e incolla un path su uno stroke succede
1242   // che la palette dell'immagine sorgente sia vuota. Non mi sembra sbagliato
1243   // mettere comunque un test qui
1244   if (srcPlt) mergePalette(tarPlt, styleTable, srcPlt, usedStyles);
1245 
1246   return mergeImage(img, affine, styleTable, sameStrokeId);
1247 }
1248 
1249 //-----------------------------------------------------------------------------
1250 
mergeImage(const TVectorImageP & img,const TAffine & affine,const std::map<int,int> & styleTable,bool sameStrokeId)1251 int TVectorImage::mergeImage(const TVectorImageP &img, const TAffine &affine,
1252                              const std::map<int, int> &styleTable,
1253                              bool sameStrokeId) {
1254   int imageSize = img->getStrokeCount();
1255   if (imageSize == 0) return 0;
1256   QMutexLocker sl(m_imp->m_mutex);
1257 
1258   m_imp->m_computedAlmostOnce |= img->m_imp->m_computedAlmostOnce;
1259 
1260   std::vector<int> changedStrokeArray(imageSize);
1261 
1262   img->m_imp->reindexGroups(*m_imp);
1263 
1264   int i;
1265   int insertAt = 0;
1266 
1267   if (m_imp->m_insideGroup !=
1268       TGroupId())  // if is inside a group, new image is put in that group.
1269   {
1270     TGroupId groupId;
1271     for (i = m_imp->m_strokes.size() - 1; i >= 0; i--) {
1272       if (m_imp->m_insideGroup.isParentOf(m_imp->m_strokes[i]->m_groupId)) {
1273         insertAt = i + 1;
1274         groupId  = m_imp->m_strokes[i]->m_groupId;
1275         break;
1276       }
1277     }
1278     if (insertAt != 0) {
1279       for (i = 0; i < (int)img->m_imp->m_strokes.size(); i++) {
1280         if (!img->m_imp->m_strokes[i]->m_groupId.isGrouped()) {
1281           img->m_imp->m_strokes[i]->m_groupId = groupId;
1282         } else {
1283           img->m_imp->m_strokes[i]->m_groupId =
1284               TGroupId(groupId, img->m_imp->m_strokes[i]->m_groupId);
1285         }
1286       }
1287     }
1288   }
1289 
1290   // si fondono l'ultimo gruppo ghost della vecchia a e il primo della nuova
1291 
1292   else if (!m_imp->m_strokes.empty() &&
1293            m_imp->m_strokes.back()->m_groupId.isGrouped(true) != 0 &&
1294            img->m_imp->m_strokes[0]->m_groupId.isGrouped(true) != 0) {
1295     TGroupId idNew = m_imp->m_strokes.back()->m_groupId,
1296              idOld = img->m_imp->m_strokes[0]->m_groupId;
1297     for (i = 0; i < (int)img->m_imp->m_strokes.size() &&
1298                 img->m_imp->m_strokes[i]->m_groupId == idOld;
1299          i++)
1300       img->m_imp->m_strokes[i]->m_groupId = idNew;
1301   }
1302 
1303   // merge dell'immagine
1304   std::map<int, int>::const_iterator styleTableIt;
1305   int oldSize = getStrokeCount();
1306 
1307   for (i = 0; i < imageSize; i++) {
1308     VIStroke *srcStroke = img->m_imp->m_strokes[i];
1309     VIStroke *tarStroke = new VIStroke(*srcStroke, sameStrokeId);
1310 
1311     int styleId;
1312     // cambio i colori delle regioni
1313     std::list<TEdge *>::const_iterator it   = tarStroke->m_edgeList.begin(),
1314                                        it_e = tarStroke->m_edgeList.end();
1315     for (; it != it_e; ++it) {
1316       int styleId  = (*it)->m_styleId;
1317       styleTableIt = styleTable.find(styleId);
1318       assert(styleTableIt != styleTable.end());
1319       if (styleTableIt != styleTable.end())
1320         (*it)->m_styleId = styleTableIt->second;
1321     }
1322 
1323     tarStroke->m_s->transform(affine, true);
1324     int strokeId = srcStroke->m_s->getId();
1325     if (getStrokeById(strokeId) == 0) tarStroke->m_s->setId(strokeId);
1326 
1327     // cambio i colori dello stroke
1328     styleId      = srcStroke->m_s->getStyle();
1329     styleTableIt = styleTable.find(styleId);
1330     assert(styleTableIt != styleTable.end());
1331     if (styleTableIt != styleTable.end())
1332       tarStroke->m_s->setStyle(styleTableIt->second);
1333     if (insertAt == 0) {
1334       m_imp->m_strokes.push_back(tarStroke);
1335       changedStrokeArray[i] = oldSize + i;
1336     } else {
1337       std::vector<VIStroke *>::iterator it = m_imp->m_strokes.begin();
1338       advance(it, insertAt + i);
1339       m_imp->m_strokes.insert(it, tarStroke);
1340       changedStrokeArray[i] = insertAt + i;
1341     }
1342   }
1343   if (insertAt > 0) {
1344     // for (i=changedStrokeArray.back()+1; i<m_imp->m_strokes.size(); i++)
1345     //  changedStrokeArray.push_back(i);
1346     m_imp->reindexEdges(changedStrokeArray, true);
1347   }
1348 
1349   notifyChangedStrokes(changedStrokeArray, std::vector<TStroke *>(), false);
1350 
1351 #ifdef _DEBUG
1352   checkIntersections();
1353 #endif
1354 
1355   return insertAt;
1356 }
1357 
1358 //-----------------------------------------------------------------------------
1359 
reindexGroups(TVectorImage::Imp & img)1360 void TVectorImage::Imp::reindexGroups(TVectorImage::Imp &img) {
1361   UINT i, j;
1362   int newMax      = img.m_maxGroupId;
1363   int newMaxGhost = img.m_maxGhostGroupId;
1364   for (i = 0; i < m_strokes.size(); i++) {
1365     VIStroke *s = m_strokes[i];
1366     if (s->m_groupId.m_id.empty()) continue;
1367     if (s->m_groupId.m_id[0] > 0)
1368       for (j = 0; j < s->m_groupId.m_id.size(); j++) {
1369         s->m_groupId.m_id[j] += img.m_maxGroupId;
1370         newMax = std::max(newMax, s->m_groupId.m_id[j]);
1371       }
1372     else
1373       for (j = 0; j < s->m_groupId.m_id.size(); j++) {
1374         s->m_groupId.m_id[j] -= img.m_maxGhostGroupId;
1375         newMaxGhost = std::max(newMaxGhost, -s->m_groupId.m_id[j]);
1376       }
1377   }
1378   m_maxGroupId = img.m_maxGroupId = newMax;
1379   m_maxGhostGroupId = img.m_maxGhostGroupId = newMaxGhost;
1380 }
1381 
1382 //-----------------------------------------------------------------------------
1383 
mergeImage(const std::vector<const TVectorImage * > & images)1384 void TVectorImage::mergeImage(const std::vector<const TVectorImage *> &images) {
1385   UINT oldSize = getStrokeCount();
1386   std::vector<int> changedStrokeArray;
1387   const TVectorImage *img;
1388   int index;
1389 
1390   if (m_imp->m_insideGroup != TGroupId()) {
1391     for (index = m_imp->m_strokes.size() - 1; index > -1; index--)
1392       if (m_imp->m_insideGroup.isParentOf(m_imp->m_strokes[index]->m_groupId))
1393         break;
1394     assert(index > -1);
1395   } else
1396     index = getStrokeCount() - 1;
1397 
1398   for (UINT j = 0; j < images.size(); ++j) {
1399     img = images[j];
1400     if (img->getStrokeCount() == 0) continue;
1401 
1402     img->m_imp->reindexGroups(*m_imp);
1403 
1404     int i = 0;
1405     /*if (!m_imp->m_strokes.empty() &&
1406 m_imp->m_strokes[index-1]->m_groupId.isGrouped(true)!=0 &&
1407 img->m_imp->m_strokes[0]->m_groupId.isGrouped(true)!=0)
1408 {
1409 assert(false);
1410 TGroupId idNew = m_imp->m_strokes[index]->m_groupId, idOld =
1411 img->m_imp->m_strokes[0]->m_groupId;
1412 for  (;i<(int)img->m_imp->m_strokes.size() &&
1413 img->m_imp->m_strokes[i]->m_groupId==idOld; i++)
1414 img->m_imp->m_strokes[i]->m_groupId==idNew;
1415 }*/
1416 
1417     int strokeCount = img->getStrokeCount();
1418     m_imp->m_computedAlmostOnce |= img->m_imp->m_computedAlmostOnce;
1419     for (i = 0; i < strokeCount; i++) {
1420       VIStroke *srcStroke = img->m_imp->m_strokes[i];
1421       VIStroke *tarStroke = new VIStroke(*srcStroke);
1422       int strokeId        = srcStroke->m_s->getId();
1423       if (getStrokeById(strokeId) == 0) tarStroke->m_s->setId(strokeId);
1424 
1425       index++;
1426       if (m_imp->m_insideGroup == TGroupId())
1427         m_imp->m_strokes.push_back(tarStroke);
1428       else  // if we are inside a group, the images must become part of that
1429             // group
1430       {
1431         tarStroke->m_groupId =
1432             TGroupId(m_imp->m_insideGroup, tarStroke->m_groupId);
1433         m_imp->insertStrokeAt(tarStroke, index);
1434       }
1435 
1436       changedStrokeArray.push_back(index);
1437     }
1438   }
1439 
1440   notifyChangedStrokes(changedStrokeArray, std::vector<TStroke *>(), false);
1441 }
1442 //-------------------------------------------------------------------
1443 
recomputeRegionsIfNeeded()1444 void TVectorImage::recomputeRegionsIfNeeded() {
1445   if (!m_imp->m_justLoaded) return;
1446 
1447   m_imp->m_justLoaded = false;
1448 
1449   std::vector<int> v(m_imp->m_strokes.size());
1450   int i;
1451   for (i = 0; i < (int)m_imp->m_strokes.size(); i++) v[i] = i;
1452 
1453   m_imp->notifyChangedStrokes(v, std::vector<TStroke *>(), false);
1454 }
1455 
1456 //-----------------------------------------------------------------------------
1457 
eraseStyleIds(const std::vector<int> styleIds)1458 void TVectorImage::eraseStyleIds(const std::vector<int> styleIds) {
1459   int j;
1460   for (j = 0; j < (int)styleIds.size(); j++) {
1461     int styleId = styleIds[j];
1462 
1463     int strokeCount = getStrokeCount();
1464     int i;
1465     for (i = strokeCount - 1; i >= 0; i--) {
1466       TStroke *stroke = getStroke(i);
1467       if (stroke && stroke->getStyle() == styleId) removeStroke(i);
1468     }
1469     int regionCount = getRegionCount();
1470     for (i = 0; i < regionCount; i++) {
1471       TRegion *region = getRegion(i);
1472       if (!region || region->getStyle() != styleId) continue;
1473       TPointD p;
1474       if (region->getInternalPoint(p)) fill(p, 0);
1475     }
1476   }
1477 }
1478 
1479 //-------------------------------------------------------------------
1480 
insertImage(const TVectorImageP & img,const std::vector<int> & dstIndices)1481 void TVectorImage::insertImage(const TVectorImageP &img,
1482                                const std::vector<int> &dstIndices) {
1483   UINT i;
1484   UINT imageSize = img->getStrokeCount();
1485   assert(dstIndices.size() == imageSize);
1486 
1487   // img->m_imp->reindexGroups(*m_imp);
1488   std::vector<int> changedStrokeArray(imageSize);
1489 
1490   std::vector<VIStroke *>::iterator it = m_imp->m_strokes.begin();
1491 
1492   for (i = 0; i < imageSize; i++) {
1493     assert(i == 0 || dstIndices[i] > dstIndices[i - 1]);
1494 
1495     VIStroke *srcStroke = img->m_imp->m_strokes[i];
1496     VIStroke *tarStroke = new VIStroke(*srcStroke);
1497     int strokeId        = srcStroke->m_s->getId();
1498     if (getStrokeById(strokeId) == 0) tarStroke->m_s->setId(strokeId);
1499     advance(it, (i == 0) ? dstIndices[i] : dstIndices[i] - dstIndices[i - 1]);
1500 
1501     it = m_imp->m_strokes.insert(it, tarStroke);
1502 
1503     changedStrokeArray[i] = dstIndices[i];
1504   }
1505   m_imp->reindexEdges(changedStrokeArray, true);
1506 
1507   notifyChangedStrokes(changedStrokeArray, std::vector<TStroke *>(), false);
1508   // m_imp->computeRegions();
1509 }
1510 
1511 //-----------------------------------------------------------------------------
1512 
enableRegionComputing(bool enabled,bool notIntersectingStrokes)1513 void TVectorImage::enableRegionComputing(bool enabled,
1514                                          bool notIntersectingStrokes) {
1515   m_imp->m_computeRegions         = enabled;
1516   m_imp->m_notIntersectingStrokes = notIntersectingStrokes;
1517 }
1518 
1519 //------------------------------------------------------------------------------
1520 
enableMinimizeEdges(bool enabled)1521 void TVectorImage::enableMinimizeEdges(bool enabled) {
1522   m_imp->m_minimizeEdges = enabled;
1523 }
1524 
1525 //-----------------------------------------------------------------------------
1526 
splitImage(const std::vector<int> & indices,bool removeFlag)1527 TVectorImageP TVectorImage::splitImage(const std::vector<int> &indices,
1528                                        bool removeFlag) {
1529   TVectorImageP out             = new TVectorImage;
1530   out->m_imp->m_maxGroupId      = m_imp->m_maxGroupId;
1531   out->m_imp->m_maxGhostGroupId = m_imp->m_maxGhostGroupId;
1532 
1533   std::vector<int> toBeRemoved;
1534 
1535   TPalette *vp = getPalette();
1536   if (vp) out->setPalette(vp->clone());
1537 
1538   for (UINT i = 0; i < indices.size(); ++i) {
1539     VIStroke *ref = m_imp->m_strokes[indices[i]];
1540     assert(ref);
1541     VIStroke *vs       = new VIStroke(*ref);
1542     vs->m_isNewForFill = true;
1543     out->m_imp->m_strokes.push_back(vs);
1544   }
1545 
1546   if (removeFlag) removeStrokes(indices, true, true);
1547   out->m_imp->m_areValidRegions    = false;
1548   out->m_imp->m_computedAlmostOnce = m_imp->m_computedAlmostOnce;
1549   return out;
1550 }
1551 
1552 //-----------------------------------------------------------------------------
1553 
splitSelected(bool removeFlag)1554 TVectorImageP TVectorImage::splitSelected(bool removeFlag) {
1555   TVectorImageP out = new TVectorImage;
1556   std::vector<int> toBeRemoved;
1557 
1558   for (UINT i = 0; i < getStrokeCount(); ++i) {
1559     VIStroke *ref = m_imp->m_strokes[i];
1560     assert(ref);
1561     if (ref->m_s->getFlag(TStroke::c_selected_flag)) {
1562       VIStroke *stroke = new VIStroke(*ref);
1563       out->m_imp->m_strokes.push_back(stroke);
1564       if (removeFlag) {
1565         toBeRemoved.push_back(i);
1566         //  	  removeStroke(i);
1567         //			delete ref;
1568         //  	  i--;
1569       }
1570     }
1571   }
1572   removeStrokes(toBeRemoved, true, true);
1573   out->m_imp->m_areValidRegions = false;
1574   return out;
1575 }
1576 
1577 //-----------------------------------------------------------------------------
1578 
validateRegions(bool state)1579 void TVectorImage::validateRegions(bool state) {
1580   m_imp->m_areValidRegions = state;
1581 }
1582 
1583 //-----------------------------------------------------------------------------
1584 
1585 /*
1586 void TVectorImage::invalidateBBox()
1587 {
1588   for(UINT i=0; i<getRegionCount(); i++)
1589     getRegion(i)->invalidateBBox();
1590 }
1591 */
1592 //-----------------------------------------------------------------------------
1593 
setFillData(std::unique_ptr<IntersectionBranch[]> const & v,UINT branchCount,bool doComputeRegions)1594 void TVectorImage::setFillData(std::unique_ptr<IntersectionBranch[]> const &v,
1595                                UINT branchCount, bool doComputeRegions) {
1596   m_imp->setFillData(v, branchCount, doComputeRegions);
1597 }
1598 
1599 //-----------------------------------------------------------------------------
1600 
getFillData(std::unique_ptr<IntersectionBranch[]> & v)1601 UINT TVectorImage::getFillData(std::unique_ptr<IntersectionBranch[]> &v) {
1602   return m_imp->getFillData(v);
1603 }
1604 
1605 //-----------------------------------------------------------------------------
1606 
enableStrokeStyle(int index,bool enable)1607 void TVectorImage::enableStrokeStyle(int index, bool enable) {
1608   DisabledStrokeStyles &disabledSet = getDisabledStrokeStyleSet();
1609   if (enable)
1610     disabledSet.erase(index);
1611   else
1612     disabledSet.insert(index);
1613 }
1614 
1615 //-----------------------------------------------------------------------------
1616 
isStrokeStyleEnabled(int index)1617 bool TVectorImage::isStrokeStyleEnabled(int index) {
1618   return isStrokeStyleEnabled__(index);
1619 }
1620 
1621 //-----------------------------------------------------------------------------
1622 
getUsedStyles(std::set<int> & styles) const1623 void TVectorImage::getUsedStyles(std::set<int> &styles) const {
1624   UINT strokeCount = getStrokeCount();
1625   UINT i           = 0;
1626   for (; i < strokeCount; ++i) {
1627     VIStroke *srcStroke = m_imp->m_strokes[i];
1628     int styleId         = srcStroke->m_s->getStyle();
1629     if (styleId != 0) styles.insert(styleId);
1630     std::list<TEdge *>::const_iterator it = srcStroke->m_edgeList.begin();
1631     for (; it != srcStroke->m_edgeList.end(); ++it) {
1632       styleId = (*it)->m_styleId;
1633       if (styleId != 0) styles.insert(styleId);
1634     }
1635   }
1636 }
1637 
1638 //-----------------------------------------------------------------------------
1639 
recomputeW1(double oldW,const TStroke & oldStroke,const TStroke & newStroke,double startW)1640 inline double recomputeW1(double oldW, const TStroke &oldStroke,
1641                           const TStroke &newStroke, double startW) {
1642   double oldLength = oldStroke.getLength();
1643   double newLength = newStroke.getLength();
1644 
1645   assert(startW <= oldW);
1646   assert(newLength < oldLength);
1647 
1648   double s = oldStroke.getLength(startW, oldW);
1649   assert(s <= newLength || areAlmostEqual(s, newLength, 1e-5));
1650 
1651   return newStroke.getParameterAtLength(s);
1652 }
1653 
1654 //-----------------------------------------------------------------------------
recomputeW2(double oldW,const TStroke & oldStroke,const TStroke & newStroke,double length)1655 inline double recomputeW2(double oldW, const TStroke &oldStroke,
1656                           const TStroke &newStroke, double length) {
1657   double s = oldStroke.getLength(oldW);
1658   return newStroke.getParameterAtLength(length + s);
1659 }
1660 
1661 //-----------------------------------------------------------------------------
1662 
recomputeW(double oldW,const TStroke & oldStroke,const TStroke & newStroke,bool isAtBegin)1663 inline double recomputeW(double oldW, const TStroke &oldStroke,
1664                          const TStroke &newStroke, bool isAtBegin) {
1665   double oldLength = oldStroke.getLength();
1666   double newLength = newStroke.getLength();
1667 
1668   assert(newLength < oldLength);
1669   double s =
1670       oldStroke.getLength(oldW) - ((isAtBegin) ? 0 : oldLength - newLength);
1671   assert(s <= newLength || areAlmostEqual(s, newLength, 1e-5));
1672 
1673   return newStroke.getParameterAtLength(s);
1674 }
1675 
1676 //-----------------------------------------------------------------------------
1677 #ifdef _DEBUG
checkIntersections()1678 void TVectorImage::checkIntersections() { m_imp->checkIntersections(); }
1679 #endif
1680 
1681 /*
1682 void TVectorImage::reassignStyles()
1683 {
1684   set<int> styles;
1685   UINT  strokeCount = getStrokeCount();
1686   UINT i=0;
1687 
1688   for( ; i< strokeCount; ++i)
1689     {
1690      int styleId = getStroke(i)->getStyle();
1691      if(styleId != 0) styles.insert(styleId);
1692     }
1693   UINT regionCount = getRegionCount();
1694   for( i = 0; i< regionCount; ++i)
1695     {
1696      int styleId = getRegion(i)->getStyle();
1697      if(styleId != 0) styles.insert(styleId);
1698     }
1699 
1700   map<int, int> conversionTable;
1701   for(set<int>::iterator it = styles.begin(); it != styles.end(); ++it)
1702     {
1703      int styleId = *it;
1704      conversionTable[styleId] = styleId + 13;
1705     }
1706 
1707   for( i = 0; i< strokeCount; ++i)
1708     {
1709      TStroke *stroke = getStroke(i);
1710      int styleId = stroke->getStyle();
1711      if(styleId != 0)
1712        {
1713         map<int, int>::iterator it = conversionTable.find(styleId);
1714         if(it != conversionTable.end())
1715           stroke->setStyle(it->second);
1716        }
1717     }
1718 
1719   for( i = 0; i< regionCount; ++i)
1720     {
1721      TRegion *region = getRegion(i);
1722      int styleId = region->getStyle();
1723      if(styleId != 0)
1724        {
1725         map<int, int>::iterator it = conversionTable.find(styleId);
1726         if(it != conversionTable.end())
1727           region->setStyle(it->second);
1728        }
1729     }
1730 }
1731 
1732 */
1733 
1734 //-----------------------------------------------------------------------------
1735 
isComputedRegionAlmostOnce() const1736 bool TVectorImage::isComputedRegionAlmostOnce() const {
1737   return m_imp->m_computedAlmostOnce;
1738 }
1739 
1740 //-----------------------------------------------------------------------------
1741 
splitStroke(int strokeIndex,const std::vector<DoublePair> & sortedWRanges)1742 void TVectorImage::splitStroke(int strokeIndex,
1743                                const std::vector<DoublePair> &sortedWRanges) {
1744   m_imp->splitStroke(strokeIndex, sortedWRanges);
1745 }
1746 
splitStroke(int strokeIndex,const std::vector<DoublePair> & sortedWRanges)1747 void TVectorImage::Imp::splitStroke(
1748     int strokeIndex, const std::vector<DoublePair> &sortedWRanges) {
1749   int i;
1750   VIStroke *subV = 0;
1751 
1752   if (strokeIndex >= (int)m_strokes.size() || sortedWRanges.empty()) return;
1753 
1754   VIStroke *vs     = m_strokes[strokeIndex];
1755   TGroupId groupId = vs->m_groupId;
1756 
1757   // se e' un self loop, alla fine non lo sara', e deve stare insieme
1758   // alle stroke non loopate. sposto lo stroke se serve
1759   /*
1760 {
1761 if (vs->m_s->isSelfLoop())
1762 int up = strokeIndex+1;
1763 while (up<(int)m_strokes.size() && m_strokes[up]->m_s->isSelfLoop())
1764 up++;
1765 int dn = strokeIndex-1;
1766 while (dn>=0 && m_strokes[dn]->m_s->isSelfLoop())
1767 dn--;
1768 if ((up == m_strokes.size() || up!=strokeIndex+1) && (dn<0 ||
1769 dn!=strokeIndex-1))
1770 {
1771 if (up>=(int)m_strokes.size())
1772 {
1773 assert(dn>=0);
1774 moveStroke(strokeIndex, dn+1);
1775 strokeIndex = dn+1;
1776 }
1777 else
1778 {
1779 moveStroke(strokeIndex, up-1);
1780 strokeIndex = up-1;
1781 }
1782 }
1783 }
1784 */
1785   assert(vs == m_strokes[strokeIndex]);
1786 
1787   bool toBeJoined =
1788       (vs->m_s->isSelfLoop() && sortedWRanges.front().first == 0.0 &&
1789        sortedWRanges.back().second == 1.0);
1790 
1791   int styleId = vs->m_s->getStyle();
1792   TStroke::OutlineOptions oOptions(vs->m_s->outlineOptions());
1793 
1794   m_regions.clear();
1795 
1796   std::list<TEdge *> origEdgeList;  // metto al pizzo la edge std::list della
1797                                     // stroke, perche' la erase intersection ne
1798                                     // fara' scempio
1799   std::list<TEdge *>::iterator it   = vs->m_edgeList.begin(),
1800                                it_e = vs->m_edgeList.end();
1801   for (; it != it_e; ++it) origEdgeList.push_back(new TEdge(**it, false));
1802 
1803   removeStroke(strokeIndex, false);
1804 
1805   std::vector<std::list<TEdge *>> edgeList(sortedWRanges.size());
1806   strokeIndex--;
1807 
1808   int wSize = (int)sortedWRanges.size();
1809 
1810   for (i = 0; i < wSize; i++) {
1811     assert(sortedWRanges[i].first < sortedWRanges[i].second);
1812     assert(i == wSize - 1 ||
1813            sortedWRanges[i].second <= sortedWRanges[i + 1].first);
1814     assert(sortedWRanges[i].first >= 0 && sortedWRanges[i].first <= 1);
1815     assert(sortedWRanges[i].second >= 0 && sortedWRanges[i].second <= 1);
1816 
1817     subV = new VIStroke(new TStroke(), groupId);
1818     TStroke s, dummy;
1819 
1820     if (areAlmostEqual(sortedWRanges[i].first, 0, 1e-4))
1821       s = *vs->m_s;
1822     else
1823       vs->m_s->split(sortedWRanges[i].first, dummy, s);
1824 
1825     double lenAtW0 = vs->m_s->getLength(sortedWRanges[i].first);
1826     double lenAtW1 = vs->m_s->getLength(sortedWRanges[i].second);
1827     double newW1   = s.getParameterAtLength(lenAtW1 - lenAtW0);
1828 
1829     if (areAlmostEqual(newW1, 1.0, 1e-4))
1830       *(subV->m_s) = s;
1831     else
1832       s.split(newW1, *(subV->m_s), dummy);
1833 
1834     strokeIndex++;
1835     /*assert(m_strokes[strokeIndex]->m_edgeList.empty());
1836 assert(m_strokes[strokeIndex-wSize+1]->m_edgeList.empty());*/
1837 
1838     std::list<TEdge *>::const_iterator it   = origEdgeList.begin(),
1839                                        it_e = origEdgeList.end();
1840     for (; it != it_e; ++it) {
1841       double wMin = std::min((*it)->m_w0, (*it)->m_w1);
1842       double wMax = std::max((*it)->m_w0, (*it)->m_w1);
1843 
1844       if (wMin >= sortedWRanges[i].second || wMax <= sortedWRanges[i].first)
1845         continue;
1846 
1847       TEdge *e = new TEdge(**it, false);
1848       if (wMin < sortedWRanges[i].first)
1849         wMin = 0.0;
1850       else
1851         wMin =
1852             recomputeW1(wMin, *(vs->m_s), *(subV->m_s), sortedWRanges[i].first);
1853 
1854       if (wMax > sortedWRanges[i].second)
1855         wMax = 1.0;
1856       else
1857         wMax =
1858             recomputeW1(wMax, *(vs->m_s), *(subV->m_s), sortedWRanges[i].first);
1859 
1860       if (e->m_w0 < e->m_w1)
1861         e->m_w0 = wMin, e->m_w1 = wMax;
1862       else
1863         e->m_w1 = wMin, e->m_w0 = wMax;
1864       e->m_r     = 0;
1865       e->m_s     = subV->m_s;
1866       e->m_index = strokeIndex;
1867       edgeList[i].push_back(e);
1868     }
1869     subV->m_edgeList.clear();
1870     insertStrokeAt(subV, strokeIndex);
1871     subV->m_s->setStyle(styleId);
1872     subV->m_s->outlineOptions() = oOptions;
1873   }
1874 
1875   clearPointerContainer(origEdgeList);
1876 
1877   if (toBeJoined)  // la stroke e' un loop, quindi i due choncketti iniziali e
1878                    // finali vanno joinati
1879   {
1880     VIStroke *s0           = m_strokes[strokeIndex];
1881     VIStroke *s1           = m_strokes[strokeIndex - wSize + 1];
1882     std::list<TEdge *> &l0 = edgeList.back();
1883     std::list<TEdge *> &l1 = edgeList.front();
1884 
1885     // assert(s0->m_edgeList.empty());
1886     // assert(s1->m_edgeList.empty());
1887     removeStroke(strokeIndex - wSize + 1, false);
1888 
1889     strokeIndex--;
1890     removeStroke(strokeIndex, false);
1891 
1892     VIStroke *s = new VIStroke(joinStrokes(s0->m_s, s1->m_s), groupId);
1893     insertStrokeAt(s, strokeIndex);
1894 
1895     std::list<TEdge *>::iterator it = l0.begin(), it_e = l0.end();
1896     for (; it != it_e; ++it) {
1897       (*it)->m_s     = s->m_s;
1898       (*it)->m_index = strokeIndex;
1899       (*it)->m_w0    = recomputeW2((*it)->m_w0, *(s0->m_s), *(s->m_s), 0);
1900       (*it)->m_w1    = recomputeW2((*it)->m_w1, *(s0->m_s), *(s->m_s), 0);
1901     }
1902     it            = l1.begin();
1903     double length = s0->m_s->getLength();
1904     while (it != l1.end()) {
1905       (*it)->m_s     = s->m_s;
1906       (*it)->m_index = strokeIndex;
1907       (*it)->m_w0    = recomputeW2((*it)->m_w0, *(s1->m_s), *(s->m_s), length);
1908       (*it)->m_w1    = recomputeW2((*it)->m_w1, *(s1->m_s), *(s->m_s), length);
1909       l0.push_back(*it);
1910       it = l1.erase(it);
1911     }
1912     assert(l1.empty());
1913     edgeList.erase(edgeList.begin());
1914 
1915     std::vector<DoublePair> appSortedWRanges;
1916 
1917     wSize--;
1918 
1919     delete s0;
1920     delete s1;
1921   }
1922 
1923   // checkIntersections();
1924 
1925   // double len  = e->m_s->getLength();
1926   // if (recomputeRegions)
1927 
1928   if (m_computedAlmostOnce) {
1929     computeRegions();
1930     assert((int)edgeList.size() == wSize);
1931     assert((int)m_strokes.size() > strokeIndex);
1932 
1933     for (i = 0; i < wSize; i++)
1934       transferColors(edgeList[i],
1935                      m_strokes[strokeIndex - wSize + i + 1]->m_edgeList, false,
1936                      false, false);
1937   }
1938 
1939   for (i = 0; i < wSize; i++) clearPointerContainer(edgeList[i]);
1940 
1941   delete vs;
1942 }
1943 
1944 //-----------------------------------------------------------------------------
1945 
computeEdgeList(TStroke * newS,const std::list<TEdge * > & edgeList1,bool join1AtBegin,const std::list<TEdge * > & edgeList2,bool join2AtBegin,std::list<TEdge * > & edgeList)1946 static void computeEdgeList(TStroke *newS, const std::list<TEdge *> &edgeList1,
1947                             bool join1AtBegin,
1948                             const std::list<TEdge *> &edgeList2,
1949                             bool join2AtBegin, std::list<TEdge *> &edgeList) {
1950   std::list<TEdge *>::const_iterator it;
1951 
1952   if (!edgeList1.empty()) {
1953     TStroke *s1    = edgeList1.front()->m_s;
1954     double length1 = s1->getLength();
1955     ;
1956 
1957     for (it = edgeList1.begin(); it != edgeList1.end(); ++it) {
1958       double l0 = s1->getLength((*it)->m_w0), l1 = s1->getLength((*it)->m_w1);
1959       if (join1AtBegin) l0 = length1 - l0, l1 = length1 - l1;
1960 
1961       TEdge *e         = new TEdge();
1962       e->m_toBeDeleted = true;
1963       e->m_index       = -1;
1964       e->m_s           = newS;
1965       e->m_styleId     = (*it)->m_styleId;
1966       e->m_w0          = newS->getParameterAtLength(l0);
1967       e->m_w1          = newS->getParameterAtLength(l1);
1968       edgeList.push_back(e);
1969     }
1970   }
1971 
1972   if (!edgeList2.empty()) {
1973     TStroke *s2    = edgeList2.front()->m_s;
1974     double offset  = newS->getLength(newS->getW(s2->getPoint(0.0)));
1975     double length2 = s2->getLength();
1976     for (it = edgeList2.begin(); it != edgeList2.end(); ++it) {
1977       double l0 = s2->getLength((*it)->m_w0), l1 = s2->getLength((*it)->m_w1);
1978       if (!join2AtBegin) l0 = length2 - l0, l1 = length2 - l1;
1979 
1980       TEdge *e         = new TEdge();
1981       e->m_toBeDeleted = true;
1982       e->m_index       = -1;
1983       e->m_s           = newS;
1984       e->m_styleId     = (*it)->m_styleId;
1985       e->m_w0          = newS->getParameterAtLength(offset + l0);
1986       e->m_w1          = newS->getParameterAtLength(offset + l1);
1987       edgeList.push_back(e);
1988     }
1989   }
1990 }
1991 
1992 //-----------------------------------------------------------------------------
1993 #ifdef _DEBUG
1994 
1995 //#include "tpalette.h"
1996 #include "tcolorstyles.h"
1997 
printEdges(std::ofstream & os,char * str,TPalette * plt,const std::list<TEdge * > & edges)1998 void printEdges(std::ofstream &os, char *str, TPalette *plt,
1999                 const std::list<TEdge *> &edges) {
2000   std::list<TEdge *>::const_iterator it;
2001 
2002   os << str << std::endl;
2003 
2004   for (it = edges.begin(); it != edges.end(); ++it) {
2005     TColorStyle *style = plt->getStyle((*it)->m_styleId);
2006     TPixel32 color     = style->getMainColor();
2007     os << "w0-w1:(" << (*it)->m_w0 << "-->" << (*it)->m_w1 << ")" << std::endl;
2008     os << "color=(" << color.r << "," << color.g << "," << color.b << ")"
2009        << std::endl;
2010   }
2011   os << std::endl << std::endl << std::endl;
2012 }
2013 #else
2014 #define printEdges
2015 
2016 #endif
2017 //-----------------------------------------------------------------------------
2018 
2019 #ifdef _DEBUG
printStrokes(std::ofstream & os)2020 void TVectorImage::Imp::printStrokes(std::ofstream &os) {
2021   for (int i = 0; i < (int)m_strokes.size(); i++) {
2022     os << "*****stroke #" << i << " *****";
2023     m_strokes[i]->m_s->print(os);
2024   }
2025 }
2026 
2027 #endif
2028 
2029 //-----------------------------------------------------------------------------
2030 
removeEndpoints(int strokeIndex)2031 TStroke *TVectorImage::removeEndpoints(int strokeIndex) {
2032   return m_imp->removeEndpoints(strokeIndex);
2033 }
2034 
restoreEndpoints(int index,TStroke * oldStroke)2035 void TVectorImage::restoreEndpoints(int index, TStroke *oldStroke) {
2036   m_imp->restoreEndpoints(index, oldStroke);
2037 }
2038 
2039 //-----------------------------------------------------------------------------
2040 
extendStrokeSmoothly(int index,const TThickPoint & pos,int cpIndex)2041 VIStroke *TVectorImage::Imp::extendStrokeSmoothly(int index,
2042                                                   const TThickPoint &pos,
2043                                                   int cpIndex) {
2044   TStroke *stroke  = m_strokes[index]->m_s;
2045   TGroupId groupId = m_strokes[index]->m_groupId;
2046 
2047   int cpCount = stroke->getControlPointCount();
2048   int styleId = stroke->getStyle();
2049   const TThickQuadratic *q =
2050       stroke->getChunk(cpIndex == 0 ? 0 : stroke->getChunkCount() - 1);
2051 
2052   double len    = q->getLength();
2053   double w      = exp(-len * 0.01);
2054   TThickPoint m = q->getThickP1();
2055 
2056   TThickPoint p1 =
2057       (cpIndex == 0 ? q->getThickP0() : q->getThickP2()) * (1 - w) + m * w;
2058   TThickPoint middleP = (p1 + pos) * 0.5;
2059 
2060   double angle = fabs(cross(normalize(m - middleP), normalize(pos - middleP)));
2061   if (angle < 0.05) middleP = (m + pos) * 0.5;
2062 
2063   stroke->setControlPoint(cpIndex, middleP);
2064   if (isAlmostZero(len)) {
2065     if (cpIndex == 0)
2066       stroke->setControlPoint(1,
2067                               middleP * 0.1 + stroke->getControlPoint(2) * 0.9);
2068     else
2069       stroke->setControlPoint(
2070           cpCount - 2,
2071           middleP * 0.1 + stroke->getControlPoint(cpCount - 3) * 0.9);
2072   }
2073 
2074   std::vector<TThickPoint> points(cpCount);
2075   for (int i = 0; i < cpCount - 1; i++)
2076     points[i] = stroke->getControlPoint((cpIndex == 0) ? cpCount - i - 1 : i);
2077   points[cpCount - 1] = pos;
2078 
2079   TStroke *newStroke = new TStroke(points);
2080   newStroke->setStyle(styleId);
2081   newStroke->outlineOptions() = stroke->outlineOptions();
2082   std::list<TEdge *> oldEdgeList, emptyList;
2083   computeEdgeList(newStroke, m_strokes[index]->m_edgeList, cpIndex == 0,
2084                   emptyList, 0, oldEdgeList);
2085 
2086   std::vector<int> toBeDeleted;
2087   toBeDeleted.push_back(index);
2088   removeStrokes(toBeDeleted, true, false);
2089 
2090   insertStrokeAt(new VIStroke(newStroke, groupId), index, false);
2091   computeRegions();
2092   transferColors(oldEdgeList, m_strokes[index]->m_edgeList, true, false, true);
2093 
2094   return m_strokes[index];
2095 }
2096 
2097 //-----------------------------------------------------------------------------
2098 
extendStroke(int index,const TThickPoint & p,int cpIndex)2099 VIStroke *TVectorImage::Imp::extendStroke(int index, const TThickPoint &p,
2100                                           int cpIndex) {
2101   TGroupId groupId = m_strokes[index]->m_groupId;
2102 
2103   TStroke *stroke = m_strokes[index]->m_s;
2104 
2105   TStroke *ret;
2106   int cpCount = stroke->getControlPointCount();
2107   int count   = 0;
2108   std::vector<TThickPoint> points(cpCount + 2);
2109   int i, incr = (cpIndex == 0) ? -1 : 1;
2110   for (i = ((cpIndex == 0) ? cpCount - 1 : 0); i != cpIndex + incr; i += incr)
2111     points[count++] = stroke->getControlPoint(i);
2112   TThickPoint tp(p, points[count - 1].thick);
2113   points[count++] = 0.5 * (stroke->getControlPoint(cpIndex) + tp);
2114   points[count++] = tp;
2115 
2116   TStroke *newStroke = new TStroke(points);
2117   newStroke->setStyle(stroke->getStyle());
2118   newStroke->outlineOptions() = stroke->outlineOptions();
2119   ret                         = newStroke;
2120   std::list<TEdge *> oldEdgeList, emptyList;
2121 
2122   if (m_computedAlmostOnce)
2123     computeEdgeList(newStroke, m_strokes[index]->m_edgeList, cpIndex == 0,
2124                     emptyList, false, oldEdgeList);
2125 
2126   std::vector<int> toBeDeleted;
2127   toBeDeleted.push_back(index);
2128   removeStrokes(toBeDeleted, true, false);
2129 
2130   // removeStroke(index, false);
2131 
2132   insertStrokeAt(new VIStroke(newStroke, groupId), index, false);
2133 
2134   if (m_computedAlmostOnce) {
2135     computeRegions();
2136     transferColors(oldEdgeList, m_strokes[index]->m_edgeList, true, false,
2137                    true);
2138   }
2139   return m_strokes[index];
2140 }
2141 
2142 //-----------------------------------------------------------------------------
2143 
joinStroke(int index1,int index2,int cpIndex1,int cpIndex2)2144 VIStroke *TVectorImage::Imp::joinStroke(int index1, int index2, int cpIndex1,
2145                                         int cpIndex2) {
2146   assert(m_strokes[index1]->m_groupId == m_strokes[index2]->m_groupId);
2147 
2148   TGroupId groupId = m_strokes[index1]->m_groupId;
2149 
2150   TStroke *stroke1 = m_strokes[index1]->m_s;
2151   TStroke *stroke2 = m_strokes[index2]->m_s;
2152   // TStroke* ret;
2153   int cpCount1 = stroke1->getControlPointCount();
2154   int cpCount2 = stroke2->getControlPointCount();
2155   int styleId  = stroke1->getStyle();
2156 
2157   // check if the both ends are at the same postion
2158   bool isSamePos = isAlmostZero(tdistance2(stroke1->getControlPoint(cpIndex1),
2159                                            stroke2->getControlPoint(cpIndex2)));
2160   // connecting the ends in the same shape at the same postion
2161   // means just making the shape self-looped
2162   if (isSamePos && index1 == index2) {
2163     stroke1->setSelfLoop();
2164     return m_strokes[index1];
2165   }
2166 
2167   std::vector<TThickPoint> points;
2168   int i, incr = (cpIndex1 == 0) ? -1 : 1;
2169   int start = ((cpIndex1 == 0) ? cpCount1 - 1 : 0);
2170   int end   = (isSamePos) ? cpIndex1 : cpIndex1 + incr;
2171   for (i = start; i != end; i += incr)
2172     points.push_back(stroke1->getControlPoint(i));
2173   points.push_back(0.5 * (stroke1->getControlPoint(cpIndex1) +
2174                           stroke2->getControlPoint(cpIndex2)));
2175   if (index1 != index2) {
2176     incr  = (cpIndex2 == 0) ? 1 : -1;
2177     start = (isSamePos) ? cpIndex2 + incr : cpIndex2;
2178     end   = ((cpIndex2 == 0) ? cpCount2 - 1 : 0) + incr;
2179     for (i = start; i != end; i += incr)
2180       points.push_back(stroke2->getControlPoint(i));
2181   } else
2182     points.push_back(stroke2->getControlPoint(cpIndex2));
2183 
2184   TStroke *newStroke = new TStroke(points);
2185   newStroke->setStyle(styleId);
2186   newStroke->outlineOptions() = stroke1->outlineOptions();
2187   // ret = newStroke;
2188   if (index1 == index2) newStroke->setSelfLoop();
2189   std::list<TEdge *> oldEdgeList, emptyList;
2190 
2191   computeEdgeList(
2192       newStroke, m_strokes[index1]->m_edgeList, cpIndex1 == 0,
2193       (index1 != index2) ? m_strokes[index2]->m_edgeList : emptyList,
2194       cpIndex2 == 0, oldEdgeList);
2195 
2196   std::vector<int> toBeDeleted;
2197   toBeDeleted.push_back(index1);
2198   if (index1 != index2) toBeDeleted.push_back(index2);
2199   removeStrokes(toBeDeleted, true, false);
2200 
2201   insertStrokeAt(new VIStroke(newStroke, groupId), index1, false);
2202   computeRegions();
2203   transferColors(oldEdgeList, m_strokes[index1]->m_edgeList, true, false, true);
2204   return m_strokes[index1];
2205 }
2206 
2207 //-----------------------------------------------------------------------------
2208 
joinStrokeSmoothly(int index1,int index2,int cpIndex1,int cpIndex2)2209 VIStroke *TVectorImage::Imp::joinStrokeSmoothly(int index1, int index2,
2210                                                 int cpIndex1, int cpIndex2) {
2211   assert(m_strokes[index1]->m_groupId == m_strokes[index2]->m_groupId);
2212 
2213   TGroupId groupId = m_strokes[index1]->m_groupId;
2214 
2215   TStroke *stroke1 = m_strokes[index1]->m_s;
2216   TStroke *stroke2 = m_strokes[index2]->m_s;
2217   TStroke *ret;
2218   int cpCount1 = stroke1->getControlPointCount();
2219   int cpCount2 = stroke2->getControlPointCount();
2220   int styleId  = stroke1->getStyle();
2221 
2222   int qCount1 = stroke1->getChunkCount();
2223   int qCount2 = stroke2->getChunkCount();
2224   const TThickQuadratic *q1 =
2225       stroke1->getChunk(cpIndex1 == 0 ? 0 : qCount1 - 1);
2226   const TThickQuadratic *q2 =
2227       stroke2->getChunk(cpIndex2 == 0 ? 0 : qCount2 - 1);
2228 
2229   double len1 = q1->getLength();
2230   assert(len1 >= 0);
2231   if (len1 <= 0) len1 = 0;
2232   double w1 = exp(-len1 * 0.01);
2233 
2234   double len2 = q2->getLength();
2235   assert(len2 >= 0);
2236   if (len2 <= 0) len2 = 0;
2237   double w2 = exp(-len2 * 0.01);
2238 
2239   TThickPoint extreme1 = cpIndex1 == 0 ? q1->getThickP0() : q1->getThickP2();
2240   TThickPoint extreme2 = cpIndex2 == 0 ? q2->getThickP0() : q2->getThickP2();
2241 
2242   TThickPoint m1 = q1->getThickP1();
2243   TThickPoint m2 = q2->getThickP1();
2244 
2245   TThickPoint p1 = extreme1 * (1 - w1) + m1 * w1;
2246   TThickPoint p2 = extreme2 * (1 - w2) + m2 * w2;
2247 
2248   TThickPoint middleP = (p1 + p2) * 0.5;
2249 
2250   double angle = fabs(cross(normalize(m1 - middleP), normalize(m2 - middleP)));
2251   if (angle < 0.05) middleP = (m1 + m2) * 0.5;
2252 
2253   stroke1->setControlPoint(cpIndex1, middleP);
2254   if (isAlmostZero(len1)) {
2255     if (cpIndex1 == 0)
2256       stroke1->setControlPoint(
2257           1, middleP * 0.1 + stroke1->getControlPoint(2) * 0.9);
2258     else
2259       stroke1->setControlPoint(
2260           cpCount1 - 2,
2261           middleP * 0.1 + stroke1->getControlPoint(cpCount1 - 3) * 0.9);
2262   }
2263 
2264   stroke2->setControlPoint(cpIndex2, middleP);
2265   if (isAlmostZero(len2)) {
2266     if (cpIndex2 == 0)
2267       stroke2->setControlPoint(
2268           1, middleP * 0.1 + stroke2->getControlPoint(2) * 0.9);
2269     else
2270       stroke2->setControlPoint(
2271           cpCount2 - 2,
2272           middleP * 0.1 + stroke2->getControlPoint(cpCount2 - 3) * 0.9);
2273   }
2274 
2275   if (stroke1 == stroke2) {
2276     std::list<TEdge *> oldEdgeList, emptyList;
2277     computeEdgeList(stroke1, m_strokes[index1]->m_edgeList, cpIndex1 == 0,
2278                     emptyList, false, oldEdgeList);
2279     eraseIntersection(index1);
2280     m_strokes[index1]->m_isNewForFill = true;
2281     stroke1->setSelfLoop();
2282     computeRegions();
2283     transferColors(oldEdgeList, m_strokes[index1]->m_edgeList, true, false,
2284                    true);
2285     return m_strokes[index1];
2286     // nundo->m_newStroke=new TStroke(*stroke1);
2287     // nundo->m_newStrokeId=stroke1->getId();
2288   }
2289 
2290   std::vector<TThickPoint> points;
2291   points.reserve(cpCount1 + cpCount2 - 1);
2292 
2293   int incr = (cpIndex1) ? 1 : -1;
2294   int stop = cpIndex1;
2295 
2296   int i = cpCount1 - 1 - cpIndex1;
2297   for (; i != stop; i += incr) points.push_back(stroke1->getControlPoint(i));
2298 
2299   incr = (cpIndex2) ? -1 : 1;
2300   stop = cpCount2 - 1 - cpIndex2;
2301 
2302   for (i = cpIndex2; i != stop; i += incr)
2303     points.push_back(stroke2->getControlPoint(i));
2304 
2305   points.push_back(stroke2->getControlPoint(stop));
2306 
2307   TStroke *newStroke = new TStroke(points);
2308   newStroke->setStyle(styleId);
2309   newStroke->outlineOptions() = stroke1->outlineOptions();
2310   ret                         = newStroke;
2311   // nundo->m_newStroke=new TStroke(*newStroke);
2312   // nundo->m_newStrokeId=newStroke->getId();
2313   std::list<TEdge *> oldEdgeList;
2314   // ofstream os("c:\\temp\\edges.txt");
2315 
2316   // printEdges(os, "****edgelist1", getPalette(),
2317   // m_imp->m_strokes[index1]->m_edgeList);
2318   // printEdges(os, "****edgelist2", getPalette(),
2319   // m_imp->m_strokes[index2]->m_edgeList);
2320 
2321   computeEdgeList(newStroke, m_strokes[index1]->m_edgeList, cpIndex1 == 0,
2322                   m_strokes[index2]->m_edgeList, cpIndex2 == 0, oldEdgeList);
2323   // printEdges(os, "****edgelist", getPalette(), oldEdgeList);
2324 
2325   std::vector<int> toBeDeleted;
2326   toBeDeleted.push_back(index1);
2327   toBeDeleted.push_back(index2);
2328   removeStrokes(toBeDeleted, true, false);
2329 
2330   insertStrokeAt(new VIStroke(newStroke, groupId), index1);
2331   computeRegions();
2332   transferColors(oldEdgeList, m_strokes[index1]->m_edgeList, true, false, true);
2333 
2334   return m_strokes[index1];
2335 
2336   //  TUndoManager::manager()->add(nundo);
2337 }
2338 
2339 //-----------------------------------------------------------------------------
2340 
joinStroke(int index1,int index2,int cpIndex1,int cpIndex2,bool isSmooth)2341 VIStroke *TVectorImage::joinStroke(int index1, int index2, int cpIndex1,
2342                                    int cpIndex2, bool isSmooth) {
2343   int finalStyle = -1;
2344 
2345   if (index1 > index2) {
2346     finalStyle = getStroke(index1)->getStyle();
2347     std::swap(index1, index2);
2348     std::swap(cpIndex1, cpIndex2);
2349   }
2350   /*
2351 if (index1==index2) //selfLoop!
2352 {
2353 if (index1>0 && index1<(int)getStrokeCount()-1 &&
2354   !getStroke(index1-1)->isSelfLoop() &&
2355   !getStroke(index1+1)->isSelfLoop())
2356 {
2357 for (UINT i = index1+2; i<getStrokeCount() && !getStroke(i)->isSelfLoop(); i++)
2358   ;
2359 moveStroke(index1, i-1);
2360 index1 = index2 = i-1;
2361 }
2362 }
2363 */
2364   VIStroke *ret;
2365   if (isSmooth)
2366     ret = m_imp->joinStrokeSmoothly(index1, index2, cpIndex1, cpIndex2);
2367   else
2368     ret = m_imp->joinStroke(index1, index2, cpIndex1, cpIndex2);
2369 
2370   if (finalStyle != -1) getStroke(index1)->setStyle(finalStyle);
2371   return ret;
2372 }
2373 
2374 //-----------------------------------------------------------------------------
2375 
extendStroke(int index,const TThickPoint & p,int cpIndex,bool isSmooth)2376 VIStroke *TVectorImage::extendStroke(int index, const TThickPoint &p,
2377                                      int cpIndex, bool isSmooth) {
2378   if (isSmooth)
2379     return m_imp->extendStrokeSmoothly(index, p, cpIndex);
2380   else
2381     return m_imp->extendStroke(index, p, cpIndex);
2382 }
2383 
2384 //-----------------------------------------------------------------------------
2385 
2386 //-----------------------------------------------------------------------------
2387 
operator >>(TPixel32 & pixel)2388 TInputStreamInterface &TInputStreamInterface::operator>>(TPixel32 &pixel) {
2389   return *this >> pixel.r >> pixel.g >> pixel.b >> pixel.m;
2390 }
2391 
2392 //-------------------------------------------------------------------
2393 
operator <<(const TPixel32 & pixel)2394 TOutputStreamInterface &TOutputStreamInterface::operator<<(
2395     const TPixel32 &pixel) {
2396   return *this << pixel.r << pixel.g << pixel.b << pixel.m;
2397 }
2398 
2399 //-------------------------------------------------------------------
2400 
setAutocloseTolerance(double val)2401 void TVectorImage::setAutocloseTolerance(double val) {
2402   m_imp->m_autocloseTolerance = val;
2403 }
2404 
2405 //-------------------------------------------------------------------
2406 
getAutocloseTolerance() const2407 double TVectorImage::getAutocloseTolerance() const {
2408   return m_imp->m_autocloseTolerance;
2409 }
2410 
2411 //-------------------------------------------------------------------
2412 
getMutex() const2413 TThread::Mutex *TVectorImage::getMutex() const { return m_imp->m_mutex; }
2414 
2415 //-------------------------------------------------------------------
2416 
areaFill(TStroke * stroke,int index,bool m_onlyUnfilled)2417 void TVectorImage::areaFill(TStroke *stroke, int index, bool m_onlyUnfilled) {
2418   TVectorImage v;
2419   v.addStroke(stroke);
2420   v.findRegions();
2421 
2422   for (UINT i = 0; i < v.getRegionCount(); i++)
2423     for (UINT j = 0; j < getRegionCount(); j++) {
2424       if (m_imp->m_insideGroup != TGroupId() &&
2425           !m_imp->m_insideGroup.isParentOf(
2426               m_imp->m_strokes[getRegion(j)->getEdge(0)->m_index]->m_groupId))
2427         continue;
2428 
2429       if (v.getRegion(i)->contains(*getRegion(j)))
2430         getRegion(j)->setStyle(index);
2431     }
2432 
2433   v.removeStroke(0);
2434 }
2435 
cloneVIStroke(VIStroke * vs)2436 VIStroke *cloneVIStroke(VIStroke *vs) { return new VIStroke(*vs); }
2437 
deleteVIStroke(VIStroke * vs)2438 void deleteVIStroke(VIStroke *vs) {
2439   delete vs;
2440   vs = 0;
2441 }
2442 
2443 //-------------------------------------------------------------------
2444 
sameSubGroup(int index0,int index1) const2445 bool TVectorImage::sameSubGroup(int index0, int index1) const {
2446   if (index0 < 0 || index1 < 0) return 0;
2447   return m_imp->m_strokes[index0]->m_groupId.getCommonParentDepth(
2448              m_imp->m_strokes[index1]->m_groupId) >
2449          m_imp->m_insideGroup.getDepth();
2450 }
2451 
2452 //-------------------------------------------------------------------
2453 
getCommonGroupDepth(int index0,int index1) const2454 int TVectorImage::getCommonGroupDepth(int index0, int index1) const {
2455   if (index0 < 0 || index1 < 0) return 0;
2456   return m_imp->m_strokes[index0]->m_groupId.getCommonParentDepth(
2457       m_imp->m_strokes[index1]->m_groupId);
2458 }
2459 
2460 //-------------------------------------------------------------------
2461 
ungroup(int fromIndex)2462 int TVectorImage::ungroup(int fromIndex) {
2463   m_imp->m_insideGroup = TGroupId();
2464 
2465   assert(m_imp->m_strokes[fromIndex]->m_groupId.isGrouped() != 0);
2466   std::vector<int> changedStrokes;
2467 
2468   int toIndex = fromIndex + 1;
2469 
2470   while (toIndex < (int)m_imp->m_strokes.size() &&
2471          m_imp->m_strokes[fromIndex]->m_groupId.getCommonParentDepth(
2472              m_imp->m_strokes[toIndex]->m_groupId) >= 1)
2473     toIndex++;
2474 
2475   toIndex--;
2476 
2477   TGroupId groupId;
2478 
2479   if (fromIndex > 0 &&
2480       m_imp->m_strokes[fromIndex - 1]->m_groupId.isGrouped(true) != 0)
2481     groupId = m_imp->m_strokes[fromIndex - 1]->m_groupId;
2482   else if (toIndex < (int)m_imp->m_strokes.size() - 1 &&
2483            m_imp->m_strokes[toIndex + 1]->m_groupId.isGrouped(true) != 0)
2484     groupId = m_imp->m_strokes[toIndex + 1]->m_groupId;
2485   else
2486     groupId = TGroupId(this, true);
2487 
2488   for (int i = fromIndex;
2489        i <= toIndex || (i < (int)m_imp->m_strokes.size() &&
2490                         m_imp->m_strokes[i]->m_groupId.isGrouped(true) != 0);
2491        i++) {
2492     m_imp->m_strokes[i]->m_groupId.ungroup(groupId);
2493     changedStrokes.push_back(i);
2494   }
2495 
2496   notifyChangedStrokes(changedStrokes, std::vector<TStroke *>(), false);
2497 
2498   return toIndex - fromIndex + 1;
2499 }
2500 
2501 //-------------------------------------------------------------------
2502 
isEnteredGroupStroke(int index) const2503 bool TVectorImage::isEnteredGroupStroke(int index) const {
2504   return m_imp->m_insideGroup.isParentOf(getVIStroke(index)->m_groupId);
2505 }
2506 
2507 //-------------------------------------------------------------------
2508 
enterGroup(int index)2509 bool TVectorImage::enterGroup(int index) {
2510   VIStroke *vs = getVIStroke(index);
2511 
2512   if (!vs->m_groupId.isGrouped()) return false;
2513 
2514   int newDepth = vs->m_groupId.getCommonParentDepth(m_imp->m_insideGroup) + 1;
2515 
2516   TGroupId newGroupId = vs->m_groupId;
2517 
2518   while (newGroupId.getDepth() > newDepth) newGroupId = newGroupId.getParent();
2519 
2520   if (newGroupId == m_imp->m_insideGroup) return false;
2521 
2522   m_imp->m_insideGroup = newGroupId;
2523   return true;
2524 }
2525 
2526 //-------------------------------------------------------------------
2527 
exitGroup()2528 int TVectorImage::exitGroup() {
2529   if (m_imp->m_insideGroup == TGroupId()) return -1;
2530 
2531   int i, ret = -1;
2532   for (i = 0; i < (int)m_imp->m_strokes.size(); i++) {
2533     if (m_imp->m_strokes[i]->m_groupId.getCommonParentDepth(
2534             m_imp->m_insideGroup) >= m_imp->m_insideGroup.getDepth()) {
2535       ret = i;
2536       break;
2537     }
2538   }
2539 
2540   assert(i != m_imp->m_strokes.size());
2541 
2542   m_imp->m_insideGroup = m_imp->m_insideGroup.getParent();
2543   return ret;
2544 }
2545 
2546 //-------------------------------------------------------------------
2547 
group(int fromIndex,int count)2548 void TVectorImage::group(int fromIndex, int count) {
2549   int i;
2550   assert(count >= 0);
2551   std::vector<int> changedStroke;
2552 
2553   TGroupId parent = TGroupId(this, false);
2554 
2555   for (i = 0; i < count; i++) {
2556     m_imp->m_strokes[fromIndex + i]->m_groupId =
2557         TGroupId(parent, m_imp->m_strokes[fromIndex + i]->m_groupId);
2558     changedStroke.push_back(fromIndex + i);
2559   }
2560 
2561   m_imp->rearrangeMultiGroup();  // see method's comment
2562 
2563   m_imp->regroupGhosts(changedStroke);
2564 
2565   notifyChangedStrokes(changedStroke, std::vector<TStroke *>(), false);
2566 
2567 #ifdef _DEBUG
2568   m_imp->checkGroups();
2569 #endif
2570 }
2571 
2572 //-------------------------------------------------------------------
2573 
getGroupDepth(UINT index) const2574 int TVectorImage::getGroupDepth(UINT index) const {
2575   assert(index < m_imp->m_strokes.size());
2576 
2577   return m_imp->m_strokes[index]->m_groupId.isGrouped();
2578 }
2579 
2580 //-------------------------------------------------------------------
2581 
areDifferentGroup(UINT index1,bool isRegion1,UINT index2,bool isRegion2) const2582 int TVectorImage::areDifferentGroup(UINT index1, bool isRegion1, UINT index2,
2583                                     bool isRegion2) const {
2584   return m_imp->areDifferentGroup(index1, isRegion1, index2, isRegion2);
2585 }
2586 
2587 //-------------------------------------------------------------------
2588 /*this method is tricky.
2589 it is not allow to have not-adiacent strokes  of same group.
2590 but it can happen when you group  some already-grouped strokes creating
2591 sub-groups.
2592 
2593 example: vi made of 5 strokes, before grouping  (N=no group)
2594 N
2595 N
2596 1
2597 1
2598 N
2599 after grouping became:
2600 2
2601 2
2602 2-1
2603 2-1
2604 2
2605 not allowed!
2606 
2607 this method moves strokes, so that  adiacent strokes have same group.
2608 so after calling rearrangeMultiGroup the vi became:
2609 2
2610 2
2611 2
2612 2-1
2613 2-1
2614 
2615 */
2616 
rearrangeMultiGroup()2617 void TVectorImage::Imp::rearrangeMultiGroup() {
2618   UINT i, j, k;
2619   if (m_strokes.size() <= 0) return;
2620   for (i = 0; i < m_strokes.size() - 1; i++) {
2621     if (m_strokes[i]->m_groupId.isGrouped() &&
2622         m_strokes[i + 1]->m_groupId.isGrouped() &&
2623         m_strokes[i]->m_groupId != m_strokes[i + 1]->m_groupId) {
2624       TGroupId &prevId   = m_strokes[i]->m_groupId;
2625       TGroupId &idToMove = m_strokes[i + 1]->m_groupId;
2626       for (j = i + 1;
2627            j < m_strokes.size() && m_strokes[j]->m_groupId == idToMove; j++)
2628         ;
2629       if (j != m_strokes.size()) {
2630         j--;  // now range i+1-j contains the strokes to be moved.
2631         // let's compute where to move them (after last
2632         for (k = j; k < m_strokes.size() && m_strokes[k]->m_groupId != prevId;
2633              k++)
2634           ;
2635         if (k < m_strokes.size()) {
2636           for (; k < m_strokes.size() && m_strokes[k]->m_groupId == prevId; k++)
2637             ;
2638           moveStrokes(i + 1, j - i, k, false);
2639           rearrangeMultiGroup();
2640           return;
2641         }
2642       }
2643     }
2644   }
2645 }
2646 
2647 //-------------------------------------------------------------------
2648 
areDifferentGroup(UINT index1,bool isRegion1,UINT index2,bool isRegion2) const2649 int TVectorImage::Imp::areDifferentGroup(UINT index1, bool isRegion1,
2650                                          UINT index2, bool isRegion2) const {
2651   TGroupId group1, group2;
2652 
2653   if (isRegion1) {
2654     TRegion *r = m_regions[index1];
2655     for (UINT i = 0; i < r->getEdgeCount(); i++)
2656       if (r->getEdge(i)->m_index >= 0) {
2657         group1 = m_strokes[r->getEdge(i)->m_index]->m_groupId;
2658         break;
2659       }
2660   } else
2661     group1 = m_strokes[index1]->m_groupId;
2662   if (isRegion2) {
2663     TRegion *r = m_regions[index2];
2664     for (UINT i = 0; i < r->getEdgeCount(); i++)
2665       if (r->getEdge(i)->m_index >= 0) {
2666         group2 = m_strokes[r->getEdge(i)->m_index]->m_groupId;
2667         break;
2668       }
2669   } else
2670     group2 = m_strokes[index2]->m_groupId;
2671 
2672   if (!group1 && !group2) return 0;
2673 
2674   if (group1 == group2)
2675     return -1;
2676   else
2677     return group1.getCommonParentDepth(group2);
2678 }
2679 
2680 //-------------------------------------------------------------------
2681 
getCommonParentDepth(const TGroupId & id) const2682 int TGroupId::getCommonParentDepth(const TGroupId &id) const {
2683   int size1 = m_id.size();
2684   int size2 = id.m_id.size();
2685   int count;
2686 
2687   for (count = 0; count < std::min(size1, size2); count++)
2688     if (m_id[size1 - count - 1] != id.m_id[size2 - count - 1]) break;
2689 
2690   return count;
2691 }
2692 
2693 //-------------------------------------------------------------------
2694 
TGroupId(const TGroupId & parent,const TGroupId & id)2695 TGroupId::TGroupId(const TGroupId &parent, const TGroupId &id) {
2696   assert(parent.m_id[0] > 0);
2697   assert(id.m_id.size() > 0);
2698 
2699   if (id.isGrouped(true) != 0)
2700     m_id.push_back(parent.m_id[0]);
2701   else {
2702     m_id = id.m_id;
2703     int i;
2704     for (i = 0; i < (int)parent.m_id.size(); i++)
2705       m_id.push_back(parent.m_id[i]);
2706   }
2707 }
2708 
2709 /*
2710 bool TGroupId::sameParent(const TGroupId& id) const
2711 {
2712 assert(!m_id.empty() || !id.m_id.empty());
2713 return m_id.back()==id.m_id.back();
2714 }
2715 */
2716 
getParent() const2717 TGroupId TGroupId::getParent() const {
2718   if (m_id.size() <= 1) return TGroupId();
2719 
2720   TGroupId ret = *this;
2721   ret.m_id.erase(ret.m_id.begin());
2722   return ret;
2723 }
2724 
ungroup(const TGroupId & id)2725 void TGroupId::ungroup(const TGroupId &id) {
2726   assert(id.isGrouped(true) != 0);
2727   assert(!m_id.empty());
2728 
2729   if (m_id.size() == 1)
2730     m_id[0] = id.m_id[0];
2731   else
2732     m_id.pop_back();
2733 }
2734 
operator ==(const TGroupId & id) const2735 bool TGroupId::operator==(const TGroupId &id) const {
2736   if (m_id.size() != id.m_id.size()) return false;
2737   UINT i;
2738   for (i = 0; i < m_id.size(); i++)
2739     if (m_id[i] != id.m_id[i]) return false;
2740 
2741   return true;
2742 }
2743 
operator <(const TGroupId & id) const2744 bool TGroupId::operator<(const TGroupId &id) const {
2745   assert(!m_id.empty() && !id.m_id.empty());
2746   int size1 = m_id.size();
2747   int size2 = id.m_id.size();
2748   int i;
2749   for (i = 0; i < std::min(size1, size2); i++)
2750     if (m_id[size1 - i - 1] != id.m_id[size2 - i - 1])
2751       return m_id[size1 - i - 1] < id.m_id[size2 - i - 1];
2752 
2753   return size1 < size2;
2754 }
2755 
2756 //-------------------------------------------------------------------
2757 
isGrouped(bool implicit) const2758 int TGroupId::isGrouped(bool implicit) const {
2759   assert(!m_id.empty());
2760   assert(m_id[0] != 0);
2761   if (implicit)
2762     return (m_id[0] < 0) ? 1 : 0;
2763   else
2764     return (m_id[0] > 0) ? m_id.size() : 0;
2765 }
2766 
2767 //-------------------------------------------------------------------
2768 
TGroupId(TVectorImage * vi,bool isGhost)2769 TGroupId::TGroupId(TVectorImage *vi, bool isGhost) {
2770   m_id.push_back((isGhost) ? -(++vi->m_imp->m_maxGhostGroupId)
2771                            : ++vi->m_imp->m_maxGroupId);
2772 }
2773 
2774 #ifdef _DEBUG
checkGroups()2775 void TVectorImage::Imp::checkGroups() {
2776   TGroupId currGroupId;
2777   std::set<TGroupId> groupSet;
2778   std::set<TGroupId>::iterator it;
2779   UINT i = 0;
2780 
2781   while (i < m_strokes.size()) {
2782     // assert(m_strokes[i]->m_groupId!=currGroupId);
2783     // assert(i==0 ||
2784     // m_strokes[i-1]->m_groupId.isGrouped()!=m_strokes[i]->m_groupId.isGrouped()!=0
2785     // ||
2786     //       (m_strokes[i]->m_groupId.isGrouped()!=0 &&
2787     //       m_strokes[i-1]->m_groupId!=m_strokes[i]->m_groupId));
2788 
2789     currGroupId = m_strokes[i]->m_groupId;
2790     it          = groupSet.find(currGroupId);
2791     if (it != groupSet.end())  // esisteva gia un gruppo con questo id!
2792       assert(!"errore: due gruppi con lo stesso id!");
2793     else
2794       groupSet.insert(currGroupId);
2795 
2796     while (i < m_strokes.size() && m_strokes[i]->m_groupId == currGroupId) i++;
2797   }
2798 }
2799 #endif
2800 
2801 //-------------------------------------------------------------------
2802 
canMoveStrokes(int strokeIndex,int count,int moveBefore) const2803 bool TVectorImage::canMoveStrokes(int strokeIndex, int count,
2804                                   int moveBefore) const {
2805   return m_imp->canMoveStrokes(strokeIndex, count, moveBefore);
2806 }
2807 
2808 //-------------------------------------------------------------------
2809 
2810 // verifica se si possono spostare le stroke  da strokeindex a
2811 // strokeindex+count-1 prima della posizione moveBefore;
2812 // per fare questo fa un vettore in cui mette tutti i gruppi nella  posizione
2813 // dopo lo
2814 // spostamento e verifica che sia un configurazione di gruppi ammessa.
2815 
canMoveStrokes(int strokeIndex,int count,int moveBefore) const2816 bool TVectorImage::Imp::canMoveStrokes(int strokeIndex, int count,
2817                                        int moveBefore) const {
2818   if (m_maxGroupId <= 1)  // non ci sono gruppi!
2819     return true;
2820 
2821   int i, j = 0;
2822 
2823   std::vector<TGroupId> groupsAfterMoving(m_strokes.size());
2824   if (strokeIndex < moveBefore) {
2825     for (i = 0; i < strokeIndex; i++)
2826       groupsAfterMoving[j++] = m_strokes[i]->m_groupId;
2827 
2828     for (i = strokeIndex + count; i < moveBefore; i++)
2829       groupsAfterMoving[j++] = m_strokes[i]->m_groupId;
2830 
2831     for (i = strokeIndex; i < strokeIndex + count; i++)
2832       groupsAfterMoving[j++] = m_strokes[i]->m_groupId;
2833 
2834     for (i = moveBefore; i < (int)m_strokes.size(); i++)
2835       groupsAfterMoving[j++] = m_strokes[i]->m_groupId;
2836   } else {
2837     for (i = 0; i < moveBefore; i++)
2838       groupsAfterMoving[j++] = m_strokes[i]->m_groupId;
2839 
2840     for (i = strokeIndex; i < strokeIndex + count; i++)
2841       groupsAfterMoving[j++] = m_strokes[i]->m_groupId;
2842 
2843     for (i = moveBefore; i < strokeIndex; i++)
2844       groupsAfterMoving[j++] = m_strokes[i]->m_groupId;
2845 
2846     for (i = strokeIndex + count; i < (int)m_strokes.size(); i++)
2847       groupsAfterMoving[j++] = m_strokes[i]->m_groupId;
2848   }
2849 
2850   assert(j == (int)m_strokes.size());
2851 
2852   i = 0;
2853   TGroupId currGroupId;
2854   std::set<TGroupId> groupSet;
2855 
2856   while (i < (int)groupsAfterMoving.size()) {
2857     currGroupId = groupsAfterMoving[i];
2858     if (groupSet.find(currGroupId) !=
2859         groupSet.end())  // esisteva gia un gruppo con questo id!
2860     {
2861       if (!currGroupId.isGrouped(true))  // i gruppi impliciti non contano
2862         return false;
2863     } else
2864       groupSet.insert(currGroupId);
2865 
2866     while (i < (int)groupsAfterMoving.size() &&
2867            groupsAfterMoving[i] == currGroupId)
2868       i++;
2869   }
2870 
2871   return true;
2872 }
2873 
2874 //-----------------------------------------------------------------
2875 
regroupGhosts(std::vector<int> & changedStrokes)2876 void TVectorImage::Imp::regroupGhosts(std::vector<int> &changedStrokes) {
2877   TGroupId currGroupId;
2878   std::set<TGroupId> groupMap;
2879   std::set<TGroupId>::iterator it;
2880   UINT i = 0;
2881 
2882   while (i < m_strokes.size()) {
2883     assert(m_strokes[i]->m_groupId != currGroupId);
2884     assert(i == 0 ||
2885            m_strokes[i - 1]->m_groupId.isGrouped() !=
2886                m_strokes[i]->m_groupId.isGrouped() != 0 ||
2887            (m_strokes[i]->m_groupId.isGrouped() != 0 &&
2888             m_strokes[i - 1]->m_groupId != m_strokes[i]->m_groupId));
2889 
2890     currGroupId = m_strokes[i]->m_groupId;
2891     it          = groupMap.find(currGroupId);
2892     if (it != groupMap.end())  // esisteva gia un gruppo con questo id!
2893     {
2894       if (currGroupId.isGrouped() != 0)
2895         assert(!"errore: due gruppi con lo stesso id!");
2896       else  // gruppo ghost; gli do un nuovo id
2897       {
2898         TGroupId newGroup(m_vi, true);
2899 
2900         while (i < m_strokes.size() &&
2901                m_strokes[i]->m_groupId.isGrouped(true) != 0) {
2902           m_strokes[i]->m_groupId = newGroup;
2903           changedStrokes.push_back(i);
2904           i++;
2905         }
2906       }
2907     } else {
2908       groupMap.insert(currGroupId);
2909       while (i < m_strokes.size() &&
2910              ((currGroupId.isGrouped(false) != 0 &&
2911                m_strokes[i]->m_groupId == currGroupId) ||
2912               (currGroupId.isGrouped(true) != 0 &&
2913                m_strokes[i]->m_groupId.isGrouped(true) != 0))) {
2914         if (m_strokes[i]->m_groupId != currGroupId) {
2915           m_strokes[i]->m_groupId = currGroupId;
2916           changedStrokes.push_back(i);
2917         }
2918         i++;
2919       }
2920     }
2921   }
2922 }
2923 
2924 //--------------------------------------------------------------
2925 
canEnterGroup(int strokeIndex) const2926 bool TVectorImage::canEnterGroup(int strokeIndex) const {
2927   VIStroke *vs = m_imp->m_strokes[strokeIndex];
2928 
2929   if (!vs->m_groupId.isGrouped()) return false;
2930 
2931   return m_imp->m_insideGroup == TGroupId() ||
2932          vs->m_groupId != m_imp->m_insideGroup;
2933 }
2934 
2935 //--------------------------------------------------------------
2936 
inCurrentGroup(int strokeIndex) const2937 bool TVectorImage::inCurrentGroup(int strokeIndex) const {
2938   return m_imp->inCurrentGroup(strokeIndex);
2939 }
2940 
2941 //----------------------------------------------------------------------------------
2942 
inCurrentGroup(int strokeIndex) const2943 bool TVectorImage::Imp::inCurrentGroup(int strokeIndex) const {
2944   return m_insideGroup == TGroupId() ||
2945          m_insideGroup.isParentOf(m_strokes[strokeIndex]->m_groupId);
2946 }
2947 
2948 //--------------------------------------------------------------------------------------------------
2949 
selectable(int strokeIndex) const2950 bool TVectorImage::selectable(int strokeIndex) const {
2951   return (m_imp->m_insideGroup != m_imp->m_strokes[strokeIndex]->m_groupId &&
2952           inCurrentGroup(strokeIndex));
2953 }
2954 
2955 //--------------------------------------------------------------------------------------------------
2956 namespace {
2957 
containsNoSubregion(const TRegion * r,const TPointD & p)2958 bool containsNoSubregion(const TRegion *r, const TPointD &p) {
2959   if (r->contains(p)) {
2960     for (unsigned int i = 0; i < r->getSubregionCount(); i++)
2961       if (r->getSubregion(i)->contains(p)) return false;
2962     return true;
2963   } else
2964     return false;
2965 }
2966 };  // namespace
2967 
2968 //------------------------------------------------------
2969 
getGroupByStroke(UINT index) const2970 int TVectorImage::getGroupByStroke(UINT index) const {
2971   VIStroke *viStroke = getVIStroke(index);
2972   return viStroke->m_groupId.m_id.back();
2973 }
2974 
2975 //------------------------------------------------------
2976 
getGroupByRegion(UINT index) const2977 int TVectorImage::getGroupByRegion(UINT index) const {
2978   TRegion *r = m_imp->m_regions[index];
2979   for (UINT i = 0; i < r->getEdgeCount(); i++)
2980     if (r->getEdge(i)->m_index >= 0) {
2981       return m_imp->m_strokes[r->getEdge(i)->m_index]->m_groupId.m_id.back();
2982     }
2983 
2984   return -1;
2985 }
2986 
2987 //------------------------------------------------------
2988 
pickGroup(const TPointD & pos,bool onEnteredGroup) const2989 int TVectorImage::pickGroup(const TPointD &pos, bool onEnteredGroup) const {
2990   if (onEnteredGroup && isInsideGroup() == 0) return -1;
2991 
2992   // double maxDist2 = 50*tglGetPixelSize2();
2993 
2994   int strokeIndex = getStrokeCount() - 1;
2995 
2996   while (strokeIndex >=
2997          0)  // ogni ciclo di while esplora un gruppo; ciclo sugli stroke
2998   {
2999     if (!isStrokeGrouped(strokeIndex)) {
3000       strokeIndex--;
3001       continue;
3002     }
3003 
3004     bool entered = isInsideGroup() > 0 && isEnteredGroupStroke(strokeIndex);
3005 
3006     if ((onEnteredGroup || entered) && (!onEnteredGroup || !entered)) {
3007       strokeIndex--;
3008       continue;
3009     }
3010 
3011     int currStrokeIndex = strokeIndex;
3012 
3013     while (strokeIndex >= 0 &&
3014            getCommonGroupDepth(strokeIndex, currStrokeIndex) > 0) {
3015       TStroke *s = getStroke(strokeIndex);
3016       double outT;
3017       int chunkIndex;
3018       double dist2;
3019       bool ret = s->getNearestChunk(pos, outT, chunkIndex, dist2);
3020       if (ret) {
3021         TThickPoint p = s->getChunk(chunkIndex)->getThickPoint(outT);
3022         if (p.thick < 0.1) p.thick = 1;
3023         if (sqrt(dist2) <= 1.5 * p.thick) return strokeIndex;
3024       }
3025 
3026       /*TThickPoint p = s->getThickPoint(s->getW(pos));
3027 
3028 double dist = tdistance( TThickPoint(pos,0), p);
3029 if (dist<1.2*p.thick/2.0)
3030 return strokeIndex;*/
3031       strokeIndex--;
3032     }
3033   }
3034 
3035   strokeIndex = getStrokeCount() - 1;
3036   int ret     = -1;
3037 
3038   while (strokeIndex >=
3039          0)  // ogni ciclo di while esplora un gruppo; ciclo sulle regions
3040   {
3041     if (!isStrokeGrouped(strokeIndex)) {
3042       strokeIndex--;
3043       continue;
3044     }
3045 
3046     bool entered = isInsideGroup() > 0 && isEnteredGroupStroke(strokeIndex);
3047 
3048     if ((onEnteredGroup || entered) && (!onEnteredGroup || !entered)) {
3049       strokeIndex--;
3050       continue;
3051     }
3052 
3053     TRegion *currR = 0;
3054     for (UINT regionIndex = 0; regionIndex < getRegionCount(); regionIndex++) {
3055       TRegion *r = getRegion(regionIndex);
3056 
3057       int i, regionStrokeIndex = -1;
3058       for (i = 0; i < (int)r->getEdgeCount() && regionStrokeIndex < 0; i++)
3059         regionStrokeIndex = r->getEdge(i)->m_index;
3060 
3061       if (regionStrokeIndex >= 0 &&
3062           sameSubGroup(regionStrokeIndex, strokeIndex) &&
3063           containsNoSubregion(r, pos)) {
3064         if (!currR || currR->contains(*r)) {
3065           currR = r;
3066           ret   = regionStrokeIndex;
3067         }
3068       }
3069     }
3070     if (currR != 0) {
3071       assert(m_palette);
3072       const TSolidColorStyle *st = dynamic_cast<const TSolidColorStyle *>(
3073           m_palette->getStyle(currR->getStyle()));
3074       if (!st || st->getMainColor() != TPixel::Transparent) return ret;
3075     }
3076 
3077     while (strokeIndex > 0 &&
3078            getCommonGroupDepth(strokeIndex, strokeIndex - 1) > 0)
3079       strokeIndex--;
3080     strokeIndex--;
3081   }
3082 
3083   return -1;
3084 }
3085 
3086 //------------------------------------------------------------------------------------
3087 
pickGroup(const TPointD & pos) const3088 int TVectorImage::pickGroup(const TPointD &pos) const {
3089   int index;
3090   if ((index = pickGroup(pos, true)) == -1) return pickGroup(pos, false);
3091 
3092   return index;
3093 }
3094 
3095 //--------------------------------------------------------------------------------------------------
3096