]> Shamusworld >> Repos - architektonas/blob - src/base/rs_hatch.cpp
Refactoring: Moved RS_GraphicView to GraphicView.
[architektonas] / src / base / rs_hatch.cpp
1 // rs_hatch.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  05/28/2010  Added this text. :-)
13 //
14
15 #include "rs_hatch.h"
16
17 #include <QtCore>
18 #include "drawing.h"
19 #include "graphicview.h"
20 #include "rs_information.h"
21 #include "paintintf.h"
22 #include "rs_pattern.h"
23 #include "rs_patternlist.h"
24
25 /**
26  * Constructor.
27  */
28 RS_Hatch::RS_Hatch(RS_EntityContainer * parent, const RS_HatchData & d):
29         RS_EntityContainer(parent), data(d)
30 {
31         hatch = NULL;
32         updateRunning = false;
33         needOptimization = true;
34 }
35
36 /*virtual*/ RS_Hatch::~RS_Hatch()
37 {
38 }
39
40 RS_Entity * RS_Hatch::clone()
41 {
42         RS_Hatch * t = new RS_Hatch(*this);
43 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
44 //      t->entities.setAutoDelete(entities.autoDelete());
45         t->initId();
46         t->detach();
47         t->hatch = NULL;
48         return t;
49 }
50
51 /**     @return RS2::EntityHatch */
52 /*virtual*/ RS2::EntityType RS_Hatch::rtti() const
53 {
54         return RS2::EntityHatch;
55 }
56
57 /**
58  * @return true: if this is a hatch with lines (hatch pattern),
59  *         false: if this is filled with a solid color.
60  */
61 /*virtual*/ bool RS_Hatch::isContainer() const
62 {
63         if (isSolid())
64                 return false;
65
66         return true;
67 }
68
69 /** @return Copy of data that defines the hatch. */
70 RS_HatchData RS_Hatch::getData() const
71 {
72         return data;
73 }
74
75 /**
76  * Validates the hatch.
77  */
78 bool RS_Hatch::validate()
79 {
80         bool ret = true;
81
82         // loops:
83         for(RS_Entity * l=firstEntity(RS2::ResolveNone); l!=NULL; l=nextEntity(RS2::ResolveNone))
84         {
85                 if (l->rtti() == RS2::EntityContainer)
86                 {
87                         RS_EntityContainer * loop = (RS_EntityContainer *)l;
88                         ret = loop->optimizeContours() && ret;
89                 }
90         }
91
92         return ret;
93 }
94
95 /**
96  * @return Number of loops.
97  */
98 int RS_Hatch::countLoops()
99 {
100         if (data.solid)
101                 return count();
102         else
103                 return count() - 1;
104 }
105
106 /** @return true if this is a solid fill. false if it is a pattern hatch. */
107 bool RS_Hatch::isSolid() const
108 {
109         return data.solid;
110 }
111
112 void RS_Hatch::setSolid(bool solid)
113 {
114         data.solid = solid;
115 }
116
117 QString RS_Hatch::getPattern()
118 {
119         return data.pattern;
120 }
121
122 void RS_Hatch::setPattern(const QString & pattern)
123 {
124         data.pattern = pattern;
125 }
126
127 double RS_Hatch::getScale()
128 {
129         return data.scale;
130 }
131
132 void RS_Hatch::setScale(double scale)
133 {
134         data.scale = scale;
135 }
136
137 double RS_Hatch::getAngle()
138 {
139         return data.angle;
140 }
141
142 void RS_Hatch::setAngle(double angle)
143 {
144         data.angle = angle;
145 }
146
147 /**
148  * Recalculates the borders of this hatch.
149  */
150 void RS_Hatch::calculateBorders()
151 {
152         RS_DEBUG->print("RS_Hatch::calculateBorders");
153
154         activateContour(true);
155         RS_EntityContainer::calculateBorders();
156
157         RS_DEBUG->print("RS_Hatch::calculateBorders: size: %f,%f", getSize().x, getSize().y);
158
159         activateContour(false);
160 }
161
162 /**
163  * Updates the Hatch. Called when the
164  * hatch or it's data, position, alignment, .. changes.
165  */
166 void RS_Hatch::update()
167 {
168         RS_DEBUG->print("RS_Hatch::update");
169         RS_DEBUG->print("RS_Hatch::update: contour has %d loops", count());
170
171         if (updateRunning)
172                 return;
173
174         if (updateEnabled == false)
175                 return;
176
177         if (data.solid == true)
178                 return;
179
180         RS_DEBUG->print("RS_Hatch::update");
181         updateRunning = true;
182
183         // delete old hatch:
184         if (hatch != NULL)
185         {
186                 removeEntity(hatch);
187                 hatch = NULL;
188         }
189
190         if (isUndone())
191         {
192                 updateRunning = false;
193                 return;
194         }
195
196         if (!validate())
197         {
198                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Hatch::update: invalid contour in hatch found");
199                 updateRunning = false;
200                 return;
201         }
202
203         // search pattern:
204         RS_DEBUG->print("RS_Hatch::update: requesting pattern");
205         RS_Pattern * pat = RS_PATTERNLIST->requestPattern(data.pattern);
206
207         if (pat == NULL)
208         {
209                 updateRunning = false;
210                 RS_DEBUG->print("RS_Hatch::update: requesting pattern: not found");
211                 return;
212         }
213
214         RS_DEBUG->print("RS_Hatch::update: requesting pattern: OK");
215
216         RS_DEBUG->print("RS_Hatch::update: cloning pattern");
217         pat = (RS_Pattern*)pat->clone();
218         RS_DEBUG->print("RS_Hatch::update: cloning pattern: OK");
219
220         // scale pattern
221         RS_DEBUG->print("RS_Hatch::update: scaling pattern");
222         pat->scale(Vector(0.0,0.0), Vector(data.scale, data.scale));
223         pat->calculateBorders();
224         forcedCalculateBorders();
225         RS_DEBUG->print("RS_Hatch::update: scaling pattern: OK");
226
227         // find out how many pattern-instances we need in x/y:
228         int px1, py1, px2, py2;
229         double f;
230         RS_Hatch * copy = (RS_Hatch *)this->clone();
231         copy->rotate(Vector(0.0, 0.0), -data.angle);
232         copy->forcedCalculateBorders();
233
234         // create a pattern over the whole contour.
235         Vector pSize = pat->getSize();
236         Vector cPos = getMin();
237         Vector cSize = getSize();
238
239         RS_DEBUG->print("RS_Hatch::update: pattern size: %f/%f", pSize.x, pSize.y);
240         RS_DEBUG->print("RS_Hatch::update: contour size: %f/%f", cSize.x, cSize.y);
241
242         if (cSize.x < 1.0e-6 || cSize.y < 1.0e-6 || pSize.x < 1.0e-6 || pSize.y < 1.0e-6
243                 || cSize.x > RS_MAXDOUBLE - 1 || cSize.y > RS_MAXDOUBLE - 1
244                 || pSize.x > RS_MAXDOUBLE - 1 || pSize.y > RS_MAXDOUBLE - 1)
245         {
246                 delete pat;
247                 delete copy;
248                 updateRunning = false;
249                 RS_DEBUG->print("RS_Hatch::update: contour size or pattern size too small");
250                 return;
251         }
252         // avoid huge memory consumption:
253         else if (cSize.x / pSize.x > 100 || cSize.y / pSize.y > 100)
254         {
255                 RS_DEBUG->print("RS_Hatch::update: contour size too large or pattern size too small");
256                 return;
257         }
258
259         f = copy->getMin().x/pat->getSize().x;
260         px1 = (int)floor(f);
261         f = copy->getMin().y/pat->getSize().y;
262         py1 = (int)floor(f);
263         f = copy->getMax().x/pat->getSize().x;
264         px2 = (int)ceil(f) - 1;
265         f = copy->getMax().y/pat->getSize().y;
266         py2 = (int)ceil(f) - 1;
267
268         RS_EntityContainer tmp;   // container for untrimmed lines
269
270         // adding array of patterns to tmp:
271         RS_DEBUG->print("RS_Hatch::update: creating pattern carpet");
272
273         for(int px=px1; px<=px2; px++)
274         {
275                 for(int py=py1; py<=py2; py++)
276                 {
277                         for(RS_Entity * e=pat->firstEntity(); e!=NULL; e=pat->nextEntity())
278                         {
279                                 RS_Entity * te = e->clone();
280                                 te->rotate(Vector(0.0, 0.0), data.angle);
281                                 Vector v1, v2;
282                                 v1.setPolar(px * pSize.x, data.angle);
283                                 v2.setPolar(py * pSize.y, data.angle + M_PI / 2.0);
284                                 te->move(v1 + v2);
285                                 tmp.addEntity(te);
286                         }
287                 }
288         }
289
290         delete pat;
291         pat = NULL;
292         RS_DEBUG->print("RS_Hatch::update: creating pattern carpet: OK");
293
294         RS_DEBUG->print("RS_Hatch::update: cutting pattern carpet");
295         // cut pattern to contour shape:
296         RS_EntityContainer tmp2;   // container for small cut lines
297         RS_Line * line = NULL;
298         RS_Arc * arc = NULL;
299         RS_Circle * circle = NULL;
300
301         for(RS_Entity * e=tmp.firstEntity(); e!=NULL; e=tmp.nextEntity())
302         {
303                 Vector startPoint;
304                 Vector endPoint;
305                 Vector center = Vector(false);
306                 bool reversed;
307
308                 if (e->rtti() == RS2::EntityLine)
309                 {
310                         line = (RS_Line *)e;
311                         arc = NULL;
312                         circle = NULL;
313                         startPoint = line->getStartpoint();
314                         endPoint = line->getEndpoint();
315                         center = Vector(false);
316                         reversed = false;
317                 }
318                 else if (e->rtti() == RS2::EntityArc)
319                 {
320                         arc = (RS_Arc *)e;
321                         line = NULL;
322                         circle = NULL;
323                         startPoint = arc->getStartpoint();
324                         endPoint = arc->getEndpoint();
325                         center = arc->getCenter();
326                         reversed = arc->isReversed();
327                 }
328                 else if (e->rtti() == RS2::EntityCircle)
329                 {
330                         circle = (RS_Circle *)e;
331                         line = NULL;
332                         arc = NULL;
333                         startPoint = circle->getCenter() + Vector(circle->getRadius(), 0.0);
334                         endPoint = startPoint;
335                         center = circle->getCenter();
336                         reversed = false;
337                 }
338                 else
339                 {
340                         continue;
341                 }
342
343                 // getting all intersections of this pattern line with the contour:
344                 QList<Vector *> is;
345 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
346 //        is.setAutoDelete(true);
347                 is.append(new Vector(startPoint));
348
349                 for(RS_Entity * loop=firstEntity(); loop!=NULL; loop=nextEntity())
350                 {
351                         if (loop->isContainer())
352                         {
353                                 for(RS_Entity * p=((RS_EntityContainer *)loop)->firstEntity(); p!=NULL; p=((RS_EntityContainer*)loop)->nextEntity())
354                                 {
355                                         VectorSolutions sol = RS_Information::getIntersection(e, p, true);
356
357                                         for(int i=0; i<=1; ++i)
358                                         {
359                                                 if (sol.get(i).valid)
360                                                 {
361                                                         is.append(new Vector(sol.get(i)));
362                                                         RS_DEBUG->print("  pattern line intersection: %f/%f", sol.get(i).x, sol.get(i).y);
363                                                 }
364                                         }
365                                 }
366                         }
367                 }
368
369                 is.append(new Vector(endPoint));
370
371                 // sort the intersection points into is2:
372                 Vector sp = startPoint;
373                 double sa = center.angleTo(sp);
374 //              Q3PtrList<Vector> is2;
375                 QList<Vector *> is2;
376 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
377 //              is2.setAutoDelete(true);
378                 bool done;
379                 double minDist;
380                 double dist = 0.0;
381                 Vector * av;
382                 Vector last = Vector(false);
383
384                 do
385                 {
386                         done = true;
387                         minDist = RS_MAXDOUBLE;
388                         av = NULL;
389
390 //                      for(Vector * v=is.first(); v!=NULL; v=is.next())
391                         for(int i=0; i<is.size(); i++)
392                         {
393                                 Vector * v = is[i];
394
395                                 if (line != NULL)
396                                 {
397                                         dist = sp.distanceTo(*v);
398                                 }
399                                 else if (arc != NULL || circle != NULL)
400                                 {
401                                         double a = center.angleTo(*v);
402
403                                         if (reversed)
404                                         {
405                                                 if (a > sa)
406                                                 {
407                                                         a -= 2 * M_PI;
408                                                 }
409
410                                                 dist = sa - a;
411                                         }
412                                         else
413                                         {
414                                                 if (a < sa)
415                                                 {
416                                                         a += 2 * M_PI;
417                                                 }
418
419                                                 dist = a - sa;
420                                         }
421
422                                         if (fabs(dist - 2 * M_PI) < 1.0e-6)
423                                         {
424                                                 dist = 0.0;
425                                         }
426                                 }
427
428                                 if (dist < minDist)
429                                 {
430                                         minDist = dist;
431                                         done = false;
432                                         av = v;
433                                         //idx = is.at();
434                                 }
435                         }
436
437                         // copy to sorted list, removing double points
438                         if (!done && av != NULL)
439                         {
440                                 if (last.valid == false || last.distanceTo(*av) > 1.0e-10)
441                                 {
442                                         is2.append(new Vector(*av));
443                                         last = *av;
444                                 }
445
446 //                              is.remove(av);
447                                 int idx = is.indexOf(av);
448
449                                 if (idx != -1)
450                                         delete is.takeAt(idx);
451
452                                 av = NULL;
453                         }
454                 }
455                 while(!done);
456
457                 // add small cut lines / arcs to tmp2:
458 //              for(Vector * v1=is2.first(); v1!=NULL;)
459                 Vector * v1 = is2[0];
460
461                 for(int i=1; i<is2.size(); i++)
462                 {
463 //                      Vector * v2 = is2.next();
464                         Vector * v2 = is2[i];
465
466                         if (v1 != NULL && v2 != NULL)
467                         {
468                                 if (line != NULL)
469                                 {
470                                         tmp2.addEntity(new RS_Line(&tmp2, RS_LineData(*v1, *v2)));
471                                 }
472                                 else if (arc != NULL || circle != NULL)
473                                 {
474                                         tmp2.addEntity(new RS_Arc(&tmp2, RS_ArcData(center, center.distanceTo(*v1),
475                                                 center.angleTo(*v1), center.angleTo(*v2), reversed)));
476                                 }
477                         }
478
479                         v1 = v2;
480                 }
481         }
482
483         // updating hatch / adding entities that are inside
484         RS_DEBUG->print("RS_Hatch::update: cutting pattern carpet: OK");
485
486         // the hatch pattern entities:
487         hatch = new RS_EntityContainer(this);
488         hatch->setPen(RS_Pen(RS2::FlagInvalid));
489         hatch->setLayer(NULL);
490         hatch->setFlag(RS2::FlagTemp);
491
492         //calculateBorders();
493
494         for(RS_Entity * e=tmp2.firstEntity(); e!=NULL; e=tmp2.nextEntity())
495         {
496                 Vector middlePoint;
497                 Vector middlePoint2;
498
499                 if (e->rtti() == RS2::EntityLine)
500                 {
501                         RS_Line * line = (RS_Line *)e;
502                         middlePoint = line->getMiddlepoint();
503                         middlePoint2 = line->getNearestDist(line->getLength() / 2.1, line->getStartpoint());
504                 }
505                 else if (e->rtti() == RS2::EntityArc)
506                 {
507                         RS_Arc * arc = (RS_Arc *)e;
508                         middlePoint = arc->getMiddlepoint();
509                         middlePoint2 = arc->getNearestDist(arc->getLength() / 2.1, arc->getStartpoint());
510                 }
511                 else
512                 {
513                         middlePoint = Vector(false);
514                         middlePoint2 = Vector(false);
515                 }
516
517                 if (middlePoint.valid)
518                 {
519                         bool onContour = false;
520
521                         if (RS_Information::isPointInsideContour(middlePoint, this, &onContour)
522                                 || RS_Information::isPointInsideContour(middlePoint2, this))
523                         {
524                                 RS_Entity * te = e->clone();
525                                 te->setPen(RS_Pen(RS2::FlagInvalid));
526                                 te->setLayer(NULL);
527                                 te->reparent(hatch);
528                                 hatch->addEntity(te);
529                         }
530                 }
531         }
532
533         addEntity(hatch);
534         //getGraphic()->addEntity(rubbish);
535
536         forcedCalculateBorders();
537
538         // deactivate contour:
539         activateContour(false);
540
541         updateRunning = false;
542
543         RS_DEBUG->print("RS_Hatch::update: OK");
544 }
545
546 /**
547  * Activates of deactivates the hatch boundary.
548  */
549 void RS_Hatch::activateContour(bool on)
550 {
551         RS_DEBUG->print("RS_Hatch::activateContour: %d", (int)on);
552
553         for(RS_Entity * e=firstEntity(); e!=NULL; e=nextEntity())
554         {
555                 if (!e->isUndone())
556                 {
557                         if (!e->getFlag(RS2::FlagTemp))
558                         {
559                                 RS_DEBUG->print("RS_Hatch::activateContour: set visible");
560                                 e->setVisible(on);
561                         }
562                         else
563                         {
564                                 RS_DEBUG->print("RS_Hatch::activateContour: entity temp");
565                         }
566                 }
567                 else
568                 {
569                         RS_DEBUG->print("RS_Hatch::activateContour: entity undone");
570                 }
571         }
572
573         RS_DEBUG->print("RS_Hatch::activateContour: OK");
574 }
575
576 /**
577  * Overrides drawing of subentities. This is only ever called for solid fills.
578  */
579 void RS_Hatch::draw(PaintInterface * painter, GraphicView * view, double /*patternOffset*/)
580 {
581         if (!data.solid)
582         {
583                 for(RS_Entity * se=firstEntity(); se!=NULL; se = nextEntity())
584                         view->drawEntity(se);
585
586                 return;
587         }
588
589 //      Q3PointArray pa;
590 //      Q3PointArray jp;   // jump points
591         QPolygon pa;
592         QPolygon jp;   // jump points
593         uint s = 0;
594         uint sj = 0;
595         int lastX = 0;
596         int lastY = 0;
597         bool lastValid = false;
598
599         // loops:
600         if (needOptimization == true)
601         {
602                 for(RS_Entity * l=firstEntity(RS2::ResolveNone); l!=NULL; l=nextEntity(RS2::ResolveNone))
603                 {
604                         if (l->rtti() == RS2::EntityContainer)
605                         {
606                                 RS_EntityContainer * loop = (RS_EntityContainer *)l;
607                                 loop->optimizeContours();
608                         }
609                 }
610
611                 needOptimization = false;
612         }
613
614         // loops:
615         for(RS_Entity * l=firstEntity(RS2::ResolveNone); l!=NULL; l=nextEntity(RS2::ResolveNone))
616         {
617                 l->setLayer(getLayer());
618
619                 if (l->rtti() == RS2::EntityContainer)
620                 {
621                         RS_EntityContainer * loop = (RS_EntityContainer *)l;
622
623                         // edges:
624                         for(RS_Entity * e=loop->firstEntity(RS2::ResolveNone); e!=NULL; e=loop->nextEntity(RS2::ResolveNone))
625                         {
626                                 e->setLayer(getLayer());
627
628                                 switch (e->rtti())
629                                 {
630                                 case RS2::EntityLine:
631                                 {
632                                         RS_Line * line = (RS_Line *)e;
633
634                                         int x1 = RS_Math::round(view->toGuiX(line->getStartpoint().x));
635                                         int y1 = RS_Math::round(view->toGuiY(line->getStartpoint().y));
636                                         int x2 = RS_Math::round(view->toGuiX(line->getEndpoint().x));
637                                         int y2 = RS_Math::round(view->toGuiY(line->getEndpoint().y));
638
639                                         if (lastValid && (lastX != x1 || lastY != y1))
640                                         {
641                                                 jp.resize(++sj);
642                                                 jp.setPoint(sj - 1, x1, y1);
643                                         }
644
645                                         pa.resize(++s);
646                                         pa.setPoint(s - 1, x1, y1);
647
648                                         pa.resize(++s);
649                                         pa.setPoint(s - 1, x2, y2);
650
651                                         lastX = x2;
652                                         lastY = y2;
653                                         lastValid = true;
654                                 }
655                                         break;
656
657                                 case RS2::EntityArc:
658                                 {
659                                         RS_Arc * arc = (RS_Arc *)e;
660
661                                         int x1 = RS_Math::round(view->toGuiX(arc->getStartpoint().x));
662                                         int y1 = RS_Math::round(view->toGuiY(arc->getStartpoint().y));
663                                         int x2 = RS_Math::round(view->toGuiX(arc->getEndpoint().x));
664                                         int y2 = RS_Math::round(view->toGuiY(arc->getEndpoint().y));
665
666                                         if (lastValid && (lastX != x1 || lastY != y1))
667                                         {
668                                                 jp.resize(++sj);
669                                                 jp.setPoint(sj - 1, x1, y1);
670                                         }
671
672                                         pa.resize(++s);
673                                         pa.setPoint(s - 1, x1, y1);
674
675 //                                      Q3PointArray pa2;
676                                         QPolygon pa2;
677                                         painter->createArc(pa2, view->toGui(arc->getCenter()),
678                                                 view->toGuiDX(arc->getRadius()), arc->getAngle1(),
679                                                 arc->getAngle2(), arc->isReversed());
680
681                                         pa.resize(s + pa2.size());
682                                         pa.putPoints(s, pa2.size(), pa2);
683                                         s += pa2.size() - 1;
684
685                                         pa.resize(++s);
686                                         pa.setPoint(s - 1, x2, y2);
687
688                                         lastX = x2;
689                                         lastY = y2;
690                                         lastValid = true;
691                                 }
692                                         break;
693
694                                 case RS2::EntityCircle:
695                                 {
696                                         RS_Circle * circle = (RS_Circle *)e;
697
698                                         int x1 = RS_Math::round(view->toGuiX(circle->getCenter().x + circle->getRadius()));
699                                         int y1 = RS_Math::round(view->toGuiY(circle->getCenter().y));
700                                         int x2 = x1;
701                                         int y2 = y1;
702
703                                         if (lastValid && (lastX != x1 || lastY != y1))
704                                         {
705                                                 jp.resize(++sj);
706                                                 jp.setPoint(sj - 1, x1, y1);
707                                         }
708
709                                         pa.resize(++s);
710                                         pa.setPoint(s - 1, x1, y1);
711
712 //                                      Q3PointArray pa2;
713                                         QPolygon pa2;
714                                         painter->createArc(pa2, view->toGui(circle->getCenter()),
715                                                 view->toGuiDX(circle->getRadius()), 0.0, 2 * M_PI, false);
716
717                                         pa.resize(s + pa2.size());
718                                         pa.putPoints(s, pa2.size(), pa2);
719                                         s += pa2.size() - 1;
720
721                                         pa.resize(++s);
722                                         pa.setPoint(s - 1, x2, y2);
723
724                                         lastX = x2;
725                                         lastY = y2;
726                                         lastValid = true;
727                                 }
728                                         break;
729
730                                 default:
731                                         break;
732                                 }
733                         }
734                 }
735         }
736
737         for(int i=(int)jp.count()-1; i>=0; --i)
738         {
739                 pa.resize(++s);
740                 pa.setPoint(s - 1, jp.point(i));
741         }
742
743         painter->setBrush(painter->getPen().getColor());
744         painter->disablePen();
745         painter->drawPolygon(pa);
746 }
747
748 /*virtual*/ double RS_Hatch::getLength()
749 {
750         return -1.0;
751 }
752
753 double RS_Hatch::getDistanceToPoint(const Vector & coord, RS_Entity ** entity,
754         RS2::ResolveLevel level, double solidDist)
755 {
756         if (data.solid == true)
757         {
758                 if (entity != NULL)
759                         *entity = this;
760
761                 bool onContour;
762
763                 if (RS_Information::isPointInsideContour(coord, this, &onContour))
764                         // distance is the snap range:
765                         return solidDist;
766
767                 return RS_MAXDOUBLE;
768         }
769         else
770         {
771                 return RS_EntityContainer::getDistanceToPoint(coord, entity, level, solidDist);
772         }
773 }
774
775 void RS_Hatch::move(Vector offset)
776 {
777         RS_EntityContainer::move(offset);
778         update();
779 }
780
781 void RS_Hatch::rotate(Vector center, double angle)
782 {
783         RS_EntityContainer::rotate(center, angle);
784         data.angle = RS_Math::correctAngle(data.angle + angle);
785         update();
786 }
787
788 void RS_Hatch::scale(Vector center, Vector factor)
789 {
790         RS_EntityContainer::scale(center, factor);
791         data.scale *= factor.x;
792         update();
793 }
794
795 void RS_Hatch::mirror(Vector axisPoint1, Vector axisPoint2)
796 {
797         RS_EntityContainer::mirror(axisPoint1, axisPoint2);
798         double ang = axisPoint1.angleTo(axisPoint2);
799         data.angle = RS_Math::correctAngle(data.angle + ang*2.0);
800         update();
801 }
802
803 void RS_Hatch::stretch(Vector firstCorner, Vector secondCorner, Vector offset)
804 {
805         RS_EntityContainer::stretch(firstCorner, secondCorner, offset);
806         update();
807 }
808
809 /**
810  * Dumps the point's data to stdout.
811  */
812 std::ostream & operator<<(std::ostream & os, const RS_Hatch & p)
813 {
814         os << " Hatch: " << p.getData() << "\n";
815         return os;
816 }