# HG changeset patch # User Sebastien Jodogne # Date 1540561260 -7200 # Node ID c57e049ed07932ae7641d351478a3d0349a6d1fa # Parent dadee0f7f1b30caf26c2e0471f0e0bf2a31d1357 drawing corners for cropping diff -r dadee0f7f1b3 -r c57e049ed079 Applications/Samples/SingleFrameEditorApplication.h --- a/Applications/Samples/SingleFrameEditorApplication.h Tue Oct 23 12:05:49 2018 +0200 +++ b/Applications/Samples/SingleFrameEditorApplication.h Fri Oct 26 15:41:00 2018 +0200 @@ -49,6 +49,16 @@ typedef OriginMessage GeometryChangedMessage; typedef OriginMessage ContentChangedMessage; + + enum Corner + { + Corner_TopLeft, + Corner_TopRight, + Corner_BottomLeft, + Corner_BottomRight + }; + + class Bitmap : public boost::noncopyable { private: @@ -62,6 +72,7 @@ unsigned int cropWidth_; unsigned int cropHeight_; Matrix transform_; + Matrix transformInverse_; double pixelSpacingX_; double pixelSpacingY_; double panX_; @@ -135,6 +146,8 @@ CreateRotationMatrix(angle_), CreateOffsetMatrix(-centerX, -centerY), transform_); + + LinearAlgebra::InvertMatrix(transformInverse_, transform_); } @@ -145,7 +158,50 @@ ApplyTransform(x, y, transform_); extent.AddPoint(x, y); } - + + + void GetCornerInternal(double& x, + double& y, + Corner corner, + unsigned int cropX, + unsigned int cropY, + unsigned int cropWidth, + unsigned int cropHeight) const + { + double dx = static_cast(cropX); + double dy = static_cast(cropY); + double dwidth = static_cast(cropWidth); + double dheight = static_cast(cropHeight); + + switch (corner) + { + case Corner_TopLeft: + x = dx; + y = dy; + break; + + case Corner_TopRight: + x = dx + dwidth; + y = dy; + break; + + case Corner_BottomLeft: + x = dx; + y = dy + dheight; + break; + + case Corner_BottomRight: + x = dx + dwidth; + y = dy + dheight; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + ApplyTransform(x, y, transform_); + } + public: Bitmap() : @@ -281,8 +337,8 @@ unsigned int x, y, width, height; GetCrop(x, y, width, height); - double dx = static_cast(x) /* - 0.5 */; - double dy = static_cast(y) /* - 0.5 */; + double dx = static_cast(x); + double dy = static_cast(y); double dwidth = static_cast(width); double dheight = static_cast(height); @@ -303,26 +359,13 @@ bool Contains(double x, double y) const { - Matrix inv; - LinearAlgebra::InvertMatrix(inv, transform_); - - Vector p; - LinearAlgebra::AssignVector(p, x, y, 1); - - Vector q = LinearAlgebra::Product(inv, p); + ApplyTransform(x, y, transformInverse_); + + unsigned int cropX, cropY, cropWidth, cropHeight; + GetCrop(cropX, cropY, cropWidth, cropHeight); - if (!LinearAlgebra::IsNear(q[2], 1.0)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - else - { - printf("at: (%.02f, %.02f)\n", q[0], q[1]); - return (q[0] >= 0 && - q[1] >= 0 && - q[0] <= static_cast(width_) && - q[1] <= static_cast(height_)); - } + return (x >= cropX && x <= cropX + cropWidth && + y >= cropY && y <= cropY + cropHeight); } @@ -429,6 +472,58 @@ cairo_stroke(cr); } + + + static double Square(double x) + { + return x * x; + } + + + void GetCorner(double& x /* out */, + double& y /* out */, + Corner corner) const + { + unsigned int cropX, cropY, cropWidth, cropHeight; + GetCrop(cropX, cropY, cropWidth, cropHeight); + GetCornerInternal(x, y, corner, cropX, cropY, cropWidth, cropHeight); + } + + + bool LookupCorner(Corner& corner /* out */, + double x, + double y, + double zoom, + double viewportDistance) const + { + static const Corner CORNERS[] = { + Corner_TopLeft, + Corner_TopRight, + Corner_BottomLeft, + Corner_BottomRight + }; + + unsigned int cropX, cropY, cropWidth, cropHeight; + GetCrop(cropX, cropY, cropWidth, cropHeight); + + double threshold = Square(viewportDistance / zoom); + + for (size_t i = 0; i < 4; i++) + { + double cx, cy; + GetCornerInternal(cx, cy, CORNERS[i], cropX, cropY, cropWidth, cropHeight); + + double d = Square(cx - x) + Square(cy - y); + + if (d <= threshold) + { + corner = CORNERS[i]; + return true; + } + } + + return false; + } }; @@ -810,6 +905,18 @@ return false; } } + + + void SetWindowing(float center, + float width) + + { + hasWindowing_ = true; + windowingCenter_ = center; + windowingWidth_ = width; + + EmitMessage(ContentChangedMessage(*this)); + } size_t LoadText(const Orthanc::Font& font, @@ -818,7 +925,7 @@ { std::auto_ptr alpha(new AlphaBitmap(*this)); alpha->LoadText(font, utf8); - alpha->SetForegroundValue(foreground); + //alpha->SetForegroundValue(foreground); size_t bitmap = countBitmaps_++; @@ -856,7 +963,7 @@ } alpha->SetAlpha(block.release()); - alpha->SetForegroundValue(foreground); + //alpha->SetForegroundValue(foreground); size_t bitmap = countBitmaps_++; @@ -1042,7 +1149,8 @@ enum Tool { Tool_Move, - Tool_Rotate + Tool_Rotate, + Tool_Crop }; @@ -1287,6 +1395,32 @@ double y, IStatusBar* statusBar) { + static const double HANDLE_SIZE = 10.0; + + size_t selected; + if (stack_.GetSelectedBitmap(selected) && + tool_ == Tool_Crop) + { + BitmapStack::BitmapAccessor accessor(stack_, selected); + + BitmapStack::Corner corner; + if (accessor.GetBitmap().LookupCorner(corner, x, y, view.GetZoom(), HANDLE_SIZE)) + { + accessor.GetBitmap().GetCorner(x, y, corner); + + double z = 1.0 / view.GetZoom(); + + context.SetSourceColor(255, 0, 0); + cairo_t* cr = context.GetObject(); + cairo_set_line_width(cr, 2.0 * z); + cairo_move_to(cr, x - HANDLE_SIZE * z, y - HANDLE_SIZE * z); + cairo_line_to(cr, x + HANDLE_SIZE * z, y - HANDLE_SIZE * z); + cairo_line_to(cr, x + HANDLE_SIZE * z, y + HANDLE_SIZE * z); + cairo_line_to(cr, x - HANDLE_SIZE * z, y + HANDLE_SIZE * z); + cairo_line_to(cr, x - HANDLE_SIZE * z, y - HANDLE_SIZE * z); + cairo_stroke(cr); + } + } } virtual void MouseWheel(WorldSceneWidget& widget, @@ -1304,6 +1438,10 @@ { switch (keyChar) { + case 'c': + tool_ = Tool_Crop; + break; + case 's': widget.FitContent(); break; @@ -1624,14 +1762,16 @@ fonts.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_)); - //stack_->LoadFrame(instance, frame, false); - //stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", frame, false); - //stack_->LoadText(fonts.GetFont(0), "Hello\nworld\nBonjour, Alain", 256); - stack_->LoadTestBlock(20, 10, 256); + stack_->LoadFrame(instance, frame, false); + stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", frame, false); + stack_->LoadText(fonts.GetFont(0), "Hello\nworld\nBonjour, Alain", 256); + stack_->LoadTestBlock(100, 50, 256); mainWidget_ = new BitmapStackWidget(IObserver::broker_, *stack_, "main-widget"); mainWidget_->SetTransmitMouseOver(true); + //stack_->SetWindowing(128, 256); + mainWidgetInteractor_.reset(new Interactor(*this)); //mainWidget_->SetInteractor(*mainWidgetInteractor_); }