comparison Applications/Samples/SingleFrameEditorApplication.h @ 350:c57e049ed079 am-2

drawing corners for cropping
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 26 Oct 2018 15:41:00 +0200
parents dadee0f7f1b3
children da25d2423314
comparison
equal deleted inserted replaced
348:dadee0f7f1b3 350:c57e049ed079
47 { 47 {
48 public: 48 public:
49 typedef OriginMessage<MessageType_Widget_GeometryChanged, BitmapStack> GeometryChangedMessage; 49 typedef OriginMessage<MessageType_Widget_GeometryChanged, BitmapStack> GeometryChangedMessage;
50 typedef OriginMessage<MessageType_Widget_ContentChanged, BitmapStack> ContentChangedMessage; 50 typedef OriginMessage<MessageType_Widget_ContentChanged, BitmapStack> ContentChangedMessage;
51 51
52
53 enum Corner
54 {
55 Corner_TopLeft,
56 Corner_TopRight,
57 Corner_BottomLeft,
58 Corner_BottomRight
59 };
60
61
52 class Bitmap : public boost::noncopyable 62 class Bitmap : public boost::noncopyable
53 { 63 {
54 private: 64 private:
55 bool visible_; 65 bool visible_;
56 bool hasSize_; 66 bool hasSize_;
60 unsigned int cropX_; 70 unsigned int cropX_;
61 unsigned int cropY_; 71 unsigned int cropY_;
62 unsigned int cropWidth_; 72 unsigned int cropWidth_;
63 unsigned int cropHeight_; 73 unsigned int cropHeight_;
64 Matrix transform_; 74 Matrix transform_;
75 Matrix transformInverse_;
65 double pixelSpacingX_; 76 double pixelSpacingX_;
66 double pixelSpacingY_; 77 double pixelSpacingY_;
67 double panX_; 78 double panX_;
68 double panY_; 79 double panY_;
69 double angle_; 80 double angle_;
133 transform_ = LinearAlgebra::Product( 144 transform_ = LinearAlgebra::Product(
134 CreateOffsetMatrix(panX_ + centerX, panY_ + centerY), 145 CreateOffsetMatrix(panX_ + centerX, panY_ + centerY),
135 CreateRotationMatrix(angle_), 146 CreateRotationMatrix(angle_),
136 CreateOffsetMatrix(-centerX, -centerY), 147 CreateOffsetMatrix(-centerX, -centerY),
137 transform_); 148 transform_);
149
150 LinearAlgebra::InvertMatrix(transformInverse_, transform_);
138 } 151 }
139 152
140 153
141 void AddToExtent(Extent2D& extent, 154 void AddToExtent(Extent2D& extent,
142 double x, 155 double x,
143 double y) const 156 double y) const
144 { 157 {
145 ApplyTransform(x, y, transform_); 158 ApplyTransform(x, y, transform_);
146 extent.AddPoint(x, y); 159 extent.AddPoint(x, y);
147 } 160 }
148 161
162
163 void GetCornerInternal(double& x,
164 double& y,
165 Corner corner,
166 unsigned int cropX,
167 unsigned int cropY,
168 unsigned int cropWidth,
169 unsigned int cropHeight) const
170 {
171 double dx = static_cast<double>(cropX);
172 double dy = static_cast<double>(cropY);
173 double dwidth = static_cast<double>(cropWidth);
174 double dheight = static_cast<double>(cropHeight);
175
176 switch (corner)
177 {
178 case Corner_TopLeft:
179 x = dx;
180 y = dy;
181 break;
182
183 case Corner_TopRight:
184 x = dx + dwidth;
185 y = dy;
186 break;
187
188 case Corner_BottomLeft:
189 x = dx;
190 y = dy + dheight;
191 break;
192
193 case Corner_BottomRight:
194 x = dx + dwidth;
195 y = dy + dheight;
196 break;
197
198 default:
199 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
200 }
201
202 ApplyTransform(x, y, transform_);
203 }
204
149 205
150 public: 206 public:
151 Bitmap() : 207 Bitmap() :
152 visible_(true), 208 visible_(true),
153 hasSize_(false), 209 hasSize_(false),
279 Extent2D extent; 335 Extent2D extent;
280 336
281 unsigned int x, y, width, height; 337 unsigned int x, y, width, height;
282 GetCrop(x, y, width, height); 338 GetCrop(x, y, width, height);
283 339
284 double dx = static_cast<double>(x) /* - 0.5 */; 340 double dx = static_cast<double>(x);
285 double dy = static_cast<double>(y) /* - 0.5 */; 341 double dy = static_cast<double>(y);
286 double dwidth = static_cast<double>(width); 342 double dwidth = static_cast<double>(width);
287 double dheight = static_cast<double>(height); 343 double dheight = static_cast<double>(height);
288 344
289 AddToExtent(extent, dx, dy); 345 AddToExtent(extent, dx, dy);
290 AddToExtent(extent, dx + dwidth, dy); 346 AddToExtent(extent, dx + dwidth, dy);
301 357
302 358
303 bool Contains(double x, 359 bool Contains(double x,
304 double y) const 360 double y) const
305 { 361 {
306 Matrix inv; 362 ApplyTransform(x, y, transformInverse_);
307 LinearAlgebra::InvertMatrix(inv, transform_); 363
308 364 unsigned int cropX, cropY, cropWidth, cropHeight;
309 Vector p; 365 GetCrop(cropX, cropY, cropWidth, cropHeight);
310 LinearAlgebra::AssignVector(p, x, y, 1); 366
311 367 return (x >= cropX && x <= cropX + cropWidth &&
312 Vector q = LinearAlgebra::Product(inv, p); 368 y >= cropY && y <= cropY + cropHeight);
313
314 if (!LinearAlgebra::IsNear(q[2], 1.0))
315 {
316 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
317 }
318 else
319 {
320 printf("at: (%.02f, %.02f)\n", q[0], q[1]);
321 return (q[0] >= 0 &&
322 q[1] >= 0 &&
323 q[0] <= static_cast<double>(width_) &&
324 q[1] <= static_cast<double>(height_));
325 }
326 } 369 }
327 370
328 371
329 void SetPan(double x, 372 void SetPan(double x,
330 double y) 373 double y)
426 y = dy; 469 y = dy;
427 ApplyTransform(x, y, transform_); 470 ApplyTransform(x, y, transform_);
428 cairo_line_to(cr, x, y); 471 cairo_line_to(cr, x, y);
429 472
430 cairo_stroke(cr); 473 cairo_stroke(cr);
474 }
475
476
477 static double Square(double x)
478 {
479 return x * x;
480 }
481
482
483 void GetCorner(double& x /* out */,
484 double& y /* out */,
485 Corner corner) const
486 {
487 unsigned int cropX, cropY, cropWidth, cropHeight;
488 GetCrop(cropX, cropY, cropWidth, cropHeight);
489 GetCornerInternal(x, y, corner, cropX, cropY, cropWidth, cropHeight);
490 }
491
492
493 bool LookupCorner(Corner& corner /* out */,
494 double x,
495 double y,
496 double zoom,
497 double viewportDistance) const
498 {
499 static const Corner CORNERS[] = {
500 Corner_TopLeft,
501 Corner_TopRight,
502 Corner_BottomLeft,
503 Corner_BottomRight
504 };
505
506 unsigned int cropX, cropY, cropWidth, cropHeight;
507 GetCrop(cropX, cropY, cropWidth, cropHeight);
508
509 double threshold = Square(viewportDistance / zoom);
510
511 for (size_t i = 0; i < 4; i++)
512 {
513 double cx, cy;
514 GetCornerInternal(cx, cy, CORNERS[i], cropX, cropY, cropWidth, cropHeight);
515
516 double d = Square(cx - x) + Square(cy - y);
517
518 if (d <= threshold)
519 {
520 corner = CORNERS[i];
521 return true;
522 }
523 }
524
525 return false;
431 } 526 }
432 }; 527 };
433 528
434 529
435 class BitmapAccessor : public boost::noncopyable 530 class BitmapAccessor : public boost::noncopyable
808 else 903 else
809 { 904 {
810 return false; 905 return false;
811 } 906 }
812 } 907 }
908
909
910 void SetWindowing(float center,
911 float width)
912
913 {
914 hasWindowing_ = true;
915 windowingCenter_ = center;
916 windowingWidth_ = width;
917
918 EmitMessage(ContentChangedMessage(*this));
919 }
813 920
814 921
815 size_t LoadText(const Orthanc::Font& font, 922 size_t LoadText(const Orthanc::Font& font,
816 const std::string& utf8, 923 const std::string& utf8,
817 float foreground) 924 float foreground)
818 { 925 {
819 std::auto_ptr<AlphaBitmap> alpha(new AlphaBitmap(*this)); 926 std::auto_ptr<AlphaBitmap> alpha(new AlphaBitmap(*this));
820 alpha->LoadText(font, utf8); 927 alpha->LoadText(font, utf8);
821 alpha->SetForegroundValue(foreground); 928 //alpha->SetForegroundValue(foreground);
822 929
823 size_t bitmap = countBitmaps_++; 930 size_t bitmap = countBitmaps_++;
824 931
825 bitmaps_[bitmap] = alpha.release(); 932 bitmaps_[bitmap] = alpha.release();
826 933
854 block->GetRegion(region, padding, padding, width - 2 * padding, height - 2 * padding); 961 block->GetRegion(region, padding, padding, width - 2 * padding, height - 2 * padding);
855 Orthanc::ImageProcessing::Set(region, color); 962 Orthanc::ImageProcessing::Set(region, color);
856 } 963 }
857 964
858 alpha->SetAlpha(block.release()); 965 alpha->SetAlpha(block.release());
859 alpha->SetForegroundValue(foreground); 966 //alpha->SetForegroundValue(foreground);
860 967
861 size_t bitmap = countBitmaps_++; 968 size_t bitmap = countBitmaps_++;
862 969
863 bitmaps_[bitmap] = alpha.release(); 970 bitmaps_[bitmap] = alpha.release();
864 971
1040 { 1147 {
1041 private: 1148 private:
1042 enum Tool 1149 enum Tool
1043 { 1150 {
1044 Tool_Move, 1151 Tool_Move,
1045 Tool_Rotate 1152 Tool_Rotate,
1153 Tool_Crop
1046 }; 1154 };
1047 1155
1048 1156
1049 BitmapStack& stack_; 1157 BitmapStack& stack_;
1050 Tool tool_; 1158 Tool tool_;
1285 const ViewportGeometry& view, 1393 const ViewportGeometry& view,
1286 double x, 1394 double x,
1287 double y, 1395 double y,
1288 IStatusBar* statusBar) 1396 IStatusBar* statusBar)
1289 { 1397 {
1398 static const double HANDLE_SIZE = 10.0;
1399
1400 size_t selected;
1401 if (stack_.GetSelectedBitmap(selected) &&
1402 tool_ == Tool_Crop)
1403 {
1404 BitmapStack::BitmapAccessor accessor(stack_, selected);
1405
1406 BitmapStack::Corner corner;
1407 if (accessor.GetBitmap().LookupCorner(corner, x, y, view.GetZoom(), HANDLE_SIZE))
1408 {
1409 accessor.GetBitmap().GetCorner(x, y, corner);
1410
1411 double z = 1.0 / view.GetZoom();
1412
1413 context.SetSourceColor(255, 0, 0);
1414 cairo_t* cr = context.GetObject();
1415 cairo_set_line_width(cr, 2.0 * z);
1416 cairo_move_to(cr, x - HANDLE_SIZE * z, y - HANDLE_SIZE * z);
1417 cairo_line_to(cr, x + HANDLE_SIZE * z, y - HANDLE_SIZE * z);
1418 cairo_line_to(cr, x + HANDLE_SIZE * z, y + HANDLE_SIZE * z);
1419 cairo_line_to(cr, x - HANDLE_SIZE * z, y + HANDLE_SIZE * z);
1420 cairo_line_to(cr, x - HANDLE_SIZE * z, y - HANDLE_SIZE * z);
1421 cairo_stroke(cr);
1422 }
1423 }
1290 } 1424 }
1291 1425
1292 virtual void MouseWheel(WorldSceneWidget& widget, 1426 virtual void MouseWheel(WorldSceneWidget& widget,
1293 MouseWheelDirection direction, 1427 MouseWheelDirection direction,
1294 KeyboardModifiers modifiers, 1428 KeyboardModifiers modifiers,
1302 KeyboardModifiers modifiers, 1436 KeyboardModifiers modifiers,
1303 IStatusBar* statusBar) 1437 IStatusBar* statusBar)
1304 { 1438 {
1305 switch (keyChar) 1439 switch (keyChar)
1306 { 1440 {
1441 case 'c':
1442 tool_ = Tool_Crop;
1443 break;
1444
1307 case 's': 1445 case 's':
1308 widget.FitContent(); 1446 widget.FitContent();
1309 break; 1447 break;
1310 1448
1311 case 'm': 1449 case 'm':
1622 1760
1623 Orthanc::FontRegistry fonts; 1761 Orthanc::FontRegistry fonts;
1624 fonts.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); 1762 fonts.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
1625 1763
1626 stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_)); 1764 stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_));
1627 //stack_->LoadFrame(instance, frame, false); 1765 stack_->LoadFrame(instance, frame, false);
1628 //stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", frame, false); 1766 stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", frame, false);
1629 //stack_->LoadText(fonts.GetFont(0), "Hello\nworld\nBonjour, Alain", 256); 1767 stack_->LoadText(fonts.GetFont(0), "Hello\nworld\nBonjour, Alain", 256);
1630 stack_->LoadTestBlock(20, 10, 256); 1768 stack_->LoadTestBlock(100, 50, 256);
1631 1769
1632 mainWidget_ = new BitmapStackWidget(IObserver::broker_, *stack_, "main-widget"); 1770 mainWidget_ = new BitmapStackWidget(IObserver::broker_, *stack_, "main-widget");
1633 mainWidget_->SetTransmitMouseOver(true); 1771 mainWidget_->SetTransmitMouseOver(true);
1634 1772
1773 //stack_->SetWindowing(128, 256);
1774
1635 mainWidgetInteractor_.reset(new Interactor(*this)); 1775 mainWidgetInteractor_.reset(new Interactor(*this));
1636 //mainWidget_->SetInteractor(*mainWidgetInteractor_); 1776 //mainWidget_->SetInteractor(*mainWidgetInteractor_);
1637 } 1777 }
1638 1778
1639 1779