Mercurial > hg > orthanc-stone
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 |