]> Shamusworld >> Repos - architektonas/blob - src/base/image.cpp
Fixed thumbnail rendering in LibraryWidget and DXF detection.
[architektonas] / src / base / image.cpp
1 // image.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 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  05/28/2010  Added this text. :-)
15 //
16
17 #include "image.h"
18
19 #include "constructionline.h"
20 #include "debug.h"
21 #include "graphicview.h"
22 #include "line.h"
23 #include "paintinterface.h"
24
25 /**
26  * Constructor.
27  */
28 RS_Image::RS_Image(RS_EntityContainer * parent, const RS_ImageData & d):
29         RS_AtomicEntity(parent), data(d)
30 {
31         update();
32         calculateBorders();
33 }
34
35 /**
36  * Destructor.
37  */
38 RS_Image::~RS_Image()
39 {
40         /*if (img!=NULL) {
41                 delete[] img;
42            }*/
43 }
44
45 RS_Entity * RS_Image::clone()
46 {
47         RS_Image * i = new RS_Image(*this);
48         i->setHandle(getHandle());
49         i->initId();
50         i->update();
51         return i;
52 }
53
54 /**     @return RS2::EntityImage */
55 /*virtual*/ RS2::EntityType RS_Image::rtti() const
56 {
57         return RS2::EntityImage;
58 }
59
60 void RS_Image::update()
61 {
62         RS_DEBUG->print("RS_Image::update");
63
64         // the whole image:
65         //QImage image = QImage(data.file);
66         img = QImage(data.file);
67
68         if (!img.isNull())
69                 data.size = Vector(img.width(), img.height());
70
71         RS_DEBUG->print("RS_Image::update: OK");
72
73         /*
74            // number of small images:
75            nx = image.width()/100;
76            ny = image.height()/100;
77
78            // create small images:
79            img = new QImage*[nx];
80            RS_Pixmap pm;
81            int w,h;
82            for (int x = 0; x<nx; ++x) {
83                 img[x] = new QImage[ny];
84                 for (int y = 0; y<ny; ++y) {
85                         if (x<nx-1) {
86                                 w = 100;
87                         }
88                         else {
89                                 w = image.width()%100;
90                         }
91
92                         if (y<ny-1) {
93                                 h = 100;
94                         }
95                         else {
96                                 h = image.height()%100;
97                         }
98
99                         pm = RS_Pixmap(w, h);
100                         RS_PainterQt painter(&pm);
101                         painter.drawImage(-x*100, -y*100, image);
102                         img[x][y] = pm.convertToImage();
103                 }
104            }
105          */
106 }
107
108 /** @return Copy of data that defines the image. */
109 RS_ImageData RS_Image::getData() const
110 {
111         return data;
112 }
113
114 /** @return Insertion point of the entity */
115 /*virtual*/ Vector RS_Image::getInsertionPoint() const
116 {
117         return data.insertionPoint;
118 }
119
120 /** Sets the insertion point for the image. */
121 void RS_Image::setInsertionPoint(Vector ip)
122 {
123         data.insertionPoint = ip;
124         calculateBorders();
125 }
126
127 /** @return File name of the image. */
128 QString RS_Image::getFile() const
129 {
130         return data.file;
131 }
132
133 /** Sets the file name of the image.  */
134 void RS_Image::setFile(const QString & file)
135 {
136         data.file = file;
137 }
138
139 /** @return u Vector. Points along bottom, 1 pixel long. */
140 Vector RS_Image::getUVector() const
141 {
142         return data.uVector;
143 }
144
145 /** @return v Vector. Points along left, 1 pixel long. */
146 Vector RS_Image::getVVector() const
147 {
148         return data.vVector;
149 }
150
151 /** @return Width of image in pixels. */
152 int RS_Image::getWidth() const
153 {
154         return (int)data.size.x;
155 }
156
157 /** @return Height of image in pixels. */
158 int RS_Image::getHeight() const
159 {
160         return (int)data.size.y;
161 }
162
163 /** @return Brightness. */
164 int RS_Image::getBrightness() const
165 {
166         return data.brightness;
167 }
168
169 /** @return Contrast. */
170 int RS_Image::getContrast() const
171 {
172         return data.contrast;
173 }
174
175 /** @return Fade. */
176 int RS_Image::getFade() const
177 {
178         return data.fade;
179 }
180
181 /** @return Image definition handle. */
182 int RS_Image::getHandle() const
183 {
184         return data.handle;
185 }
186
187 /** Sets the image definition handle. */
188 void RS_Image::setHandle(int h)
189 {
190         data.handle = h;
191 }
192
193 /** @return The four corners. **/
194 VectorSolutions RS_Image::getCorners()
195 {
196         VectorSolutions sol(4);
197
198         sol.set(0, data.insertionPoint);
199         sol.set(1,
200                 data.insertionPoint + data.uVector * RS_Math::round(data.size.x));
201         sol.set(3,
202                 data.insertionPoint + data.vVector * RS_Math::round(data.size.y));
203         sol.set(2, sol.get(3) + data.uVector * RS_Math::round(data.size.x));
204
205         return sol;
206 }
207
208 /**
209  * @return image with in graphic units.
210  */
211 double RS_Image::getImageWidth()
212 {
213         return data.size.x * data.uVector.magnitude();
214 }
215
216 /**
217  * @return image height in graphic units.
218  */
219 double RS_Image::getImageHeight()
220 {
221         return data.size.y * data.vVector.magnitude();
222 }
223
224 void RS_Image::calculateBorders()
225 {
226         resetBorders();
227         VectorSolutions sol = getCorners();
228
229         for (int i = 0; i < 4; ++i)
230         {
231                 minV = Vector::minimum(minV, sol.get(i));
232                 maxV = Vector::maximum(maxV, sol.get(i));
233         }
234 }
235
236 Vector RS_Image::getNearestEndpoint(const Vector & coord, double * dist)
237 {
238         VectorSolutions corners = getCorners();
239         return corners.getClosest(coord, dist);
240 }
241
242 Vector RS_Image::getNearestPointOnEntity(const Vector & coord, bool onEntity, double * dist, RS_Entity * * entity)
243 {
244         if (entity != NULL)
245                 *entity = this;
246
247         VectorSolutions corners = getCorners();
248         VectorSolutions points(4);
249
250         RS_Line l[] = {
251                 RS_Line(NULL, RS_LineData(corners.get(0), corners.get(1))),
252                 RS_Line(NULL, RS_LineData(corners.get(1), corners.get(2))),
253                 RS_Line(NULL, RS_LineData(corners.get(2), corners.get(3))),
254                 RS_Line(NULL, RS_LineData(corners.get(3), corners.get(0)))
255         };
256
257         for (int i = 0; i < 4; ++i)
258                 points.set(i, l[i].getNearestPointOnEntity(coord, onEntity));
259
260         return points.getClosest(coord, dist);
261 }
262
263 Vector RS_Image::getNearestCenter(const Vector & coord, double * dist)
264 {
265         VectorSolutions points(4);
266         VectorSolutions corners = getCorners();
267
268         points.set(0, (corners.get(0) + corners.get(1)) / 2.0);
269         points.set(1, (corners.get(1) + corners.get(2)) / 2.0);
270         points.set(2, (corners.get(2) + corners.get(3)) / 2.0);
271         points.set(3, (corners.get(3) + corners.get(0)) / 2.0);
272
273         return points.getClosest(coord, dist);
274 }
275
276 Vector RS_Image::getNearestMiddle(const Vector & coord, double * dist)
277 {
278         return getNearestCenter(coord, dist);
279 }
280
281 Vector RS_Image::getNearestDist(double distance, const Vector & coord, double * dist)
282 {
283         VectorSolutions corners = getCorners();
284         VectorSolutions points(4);
285
286         RS_Line l[] =
287         {
288                 RS_Line(NULL, RS_LineData(corners.get(0), corners.get(1))),
289                 RS_Line(NULL, RS_LineData(corners.get(1), corners.get(2))),
290                 RS_Line(NULL, RS_LineData(corners.get(2), corners.get(3))),
291                 RS_Line(NULL, RS_LineData(corners.get(3), corners.get(0)))
292         };
293
294         for (int i = 0; i < 4; ++i)
295                 points.set(i, l[i].getNearestDist(distance, coord, dist));
296
297         return points.getClosest(coord, dist);
298 }
299
300 double RS_Image::getDistanceToPoint(const Vector & coord, RS_Entity * * entity, RS2::ResolveLevel /*level*/,        double /*solidDist*/)
301 {
302         if (entity != NULL)
303                 *entity = this;
304
305         VectorSolutions corners = getCorners();
306         double dist;
307         double minDist = RS_MAXDOUBLE;
308
309         RS_Line l[] =
310         {
311                 RS_Line(NULL, RS_LineData(corners.get(0), corners.get(1))),
312                 RS_Line(NULL, RS_LineData(corners.get(1), corners.get(2))),
313                 RS_Line(NULL, RS_LineData(corners.get(2), corners.get(3))),
314                 RS_Line(NULL, RS_LineData(corners.get(3), corners.get(0)))
315         };
316
317         for (int i = 0; i < 4; ++i)
318         {
319                 dist = l[i].getDistanceToPoint(coord, NULL);
320
321                 if (dist < minDist)
322                         minDist = dist;
323         }
324
325         return minDist;
326 }
327
328 /*virtual*/ double RS_Image::getLength()
329 {
330         return -1.0;
331 }
332
333 void RS_Image::move(Vector offset)
334 {
335         data.insertionPoint.move(offset);
336         calculateBorders();
337 }
338
339 void RS_Image::rotate(Vector center, double angle)
340 {
341         data.insertionPoint.rotate(center, angle);
342         data.uVector.rotate(angle);
343         data.vVector.rotate(angle);
344         calculateBorders();
345 }
346
347 void RS_Image::scale(Vector center, Vector factor)
348 {
349         data.insertionPoint.scale(center, factor);
350         data.uVector.scale(factor);
351         data.vVector.scale(factor);
352         calculateBorders();
353 }
354
355 void RS_Image::mirror(Vector axisPoint1, Vector axisPoint2)
356 {
357         data.insertionPoint.mirror(axisPoint1, axisPoint2);
358         data.uVector.mirror(Vector(0.0, 0.0), axisPoint2 - axisPoint1);
359         data.vVector.mirror(Vector(0.0, 0.0), axisPoint2 - axisPoint1);
360         calculateBorders();
361 }
362
363 void RS_Image::draw(PaintInterface * painter, GraphicView * view, double /*patternOffset*/)
364 {
365         if (painter == NULL || view == NULL || img.isNull())
366                 return;
367
368         // erase image:
369         //if (painter->getPen().getColor()==view->getBackground()) {
370         //      VectorSolutions sol = getCorners();
371         //
372         //}
373
374         int ox = 0;
375         int oy = 0;
376         int width = view->getWidth();
377         int height = view->getHeight();
378
379         Vector scale = Vector(view->toGuiDX(data.uVector.magnitude()),
380                         view->toGuiDY(data.vVector.magnitude()));
381         double angle = data.uVector.angle();
382
383         int startX, stopX, startY, stopY;
384
385         if (data.uVector.x > 1.0e-6 && data.vVector.y > 1.0e-6)
386         {
387                 startX = (int)((view->toGraphX(ox) - data.insertionPoint.x) / data.uVector.x) - 1;
388
389                 if (startX < 0)
390                         startX = 0;
391
392                 stopX = (int)((view->toGraphX(width) - data.insertionPoint.x) / data.uVector.x) + 1;
393
394                 if (stopX > (int)data.size.x)
395                         stopX = (int)data.size.x;
396
397                 startY = -(int)((view->toGraphY(oy) - (data.insertionPoint.y + getImageHeight()))
398                                 / data.vVector.y) - 1;
399
400                 if (startY < 0)
401                         startY = 0;
402
403                 stopY = -(int)((view->toGraphY(height) - (data.insertionPoint.y + getImageHeight()))
404                                / data.vVector.y) + 1;
405
406                 if (stopY > (int)data.size.y)
407                         stopY = (int)data.size.y;
408         }
409         else
410         {
411                 startX = 0;
412                 startY = 0;
413                 stopX = 0;
414                 stopY = 0;
415         }
416
417         painter->drawImg(img, view->toGui(data.insertionPoint), angle, scale,
418                 startX, startY, stopX - startX, stopY - startY);
419
420         if (isSelected())
421         {
422                 VectorSolutions sol = getCorners();
423
424                 painter->drawLine(view->toGui(sol.get(0)), view->toGui(sol.get(1)));
425                 painter->drawLine(view->toGui(sol.get(1)), view->toGui(sol.get(2)));
426                 painter->drawLine(view->toGui(sol.get(2)), view->toGui(sol.get(3)));
427                 painter->drawLine(view->toGui(sol.get(3)), view->toGui(sol.get(0)));
428         }
429 }
430
431 /**
432  * Dumps the point's data to stdout.
433  */
434 std::ostream & operator<<(std::ostream & os, const RS_Image & i)
435 {
436         os << " Image: " << i.getData() << "\n";
437         return os;
438 }