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