Mercurial > hg > orthanc-stone
changeset 476:a95090305dd4 am-touch-events
Introduced ControlPoint instead of Corner in the trackers and layers + drawing mask from the ControlPoints
author | am@osimis.io |
---|---|
date | Wed, 13 Feb 2019 12:04:02 +0100 |
parents | 3c28542229a3 |
children | baf8c8d68bbc |
files | Applications/Samples/SingleFrameEditorApplication.h Framework/Radiography/RadiographyLayer.cpp Framework/Radiography/RadiographyLayer.h Framework/Radiography/RadiographyLayerCropTracker.cpp Framework/Radiography/RadiographyLayerCropTracker.h Framework/Radiography/RadiographyLayerResizeTracker.cpp Framework/Radiography/RadiographyLayerResizeTracker.h Framework/Radiography/RadiographyMaskLayer.cpp Framework/Radiography/RadiographyMaskLayer.h Framework/StoneEnumerations.h |
diffstat | 10 files changed, 350 insertions(+), 217 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/Samples/SingleFrameEditorApplication.h Tue Feb 12 12:22:13 2019 +0100 +++ b/Applications/Samples/SingleFrameEditorApplication.h Wed Feb 13 12:04:02 2019 +0100 @@ -61,6 +61,7 @@ Tool_Rotate, Tool_Crop, Tool_Resize, + Tool_Mask, Tool_Windowing }; @@ -68,6 +69,7 @@ StoneApplicationContext* context_; UndoRedoStack undoRedoStack_; Tool tool_; + RadiographyMaskLayer* maskLayer_; static double GetHandleSize() @@ -80,7 +82,8 @@ RadiographyEditorInteractor(MessageBroker& broker) : IObserver(broker), context_(NULL), - tool_(Tool_Move) + tool_(Tool_Move), + maskLayer_(NULL) { } @@ -89,6 +92,10 @@ context_ = &context; } + void SetMaskLayer(RadiographyMaskLayer* maskLayer) + { + maskLayer_ = maskLayer; + } virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& worldWidget, const ViewportGeometry& view, MouseButton button, @@ -127,23 +134,32 @@ return NULL; } + else if (tool_ == Tool_Mask) + { +// maskLayer_ +// case Tool_Mask: +// return new RadiographyLayerMaskTracker +// (undoRedoStack_, widget.GetScene(), view, selected, x, y, corner); + return NULL; + } else if (tool_ == Tool_Crop || tool_ == Tool_Resize) { RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected); - Corner corner; - if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize())) + ControlPoint controlPoint; + if (accessor.GetLayer().LookupControlPoint(controlPoint, x, y, view.GetZoom(), GetHandleSize())) { switch (tool_) { case Tool_Crop: return new RadiographyLayerCropTracker - (undoRedoStack_, widget.GetScene(), view, selected, x, y, corner); + (undoRedoStack_, widget.GetScene(), view, selected, controlPoint); + case Tool_Resize: return new RadiographyLayerResizeTracker - (undoRedoStack_, widget.GetScene(), selected, x, y, corner, + (undoRedoStack_, widget.GetScene(), selected, controlPoint, (modifiers & KeyboardModifiers_Shift)); default: @@ -209,6 +225,7 @@ { return NULL; } + return NULL; } virtual void MouseOver(CairoContext& context, @@ -233,25 +250,24 @@ if (widget.LookupSelectedLayer(selected) && (tool_ == Tool_Crop || - tool_ == Tool_Resize)) + tool_ == Tool_Resize) || + tool_ == Tool_Mask) { RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected); - Corner corner; - if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize())) + ControlPoint controlPoint; + if (accessor.GetLayer().LookupControlPoint(controlPoint, x, y, view.GetZoom(), GetHandleSize())) { - accessor.GetLayer().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 - GetHandleSize() * z, y - GetHandleSize() * z); - cairo_line_to(cr, x + GetHandleSize() * z, y - GetHandleSize() * z); - cairo_line_to(cr, x + GetHandleSize() * z, y + GetHandleSize() * z); - cairo_line_to(cr, x - GetHandleSize() * z, y + GetHandleSize() * z); - cairo_line_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z); + cairo_move_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y - GetHandleSize() * z); + cairo_line_to(cr, controlPoint.x + GetHandleSize() * z, controlPoint.y - GetHandleSize() * z); + cairo_line_to(cr, controlPoint.x + GetHandleSize() * z, controlPoint.y + GetHandleSize() * z); + cairo_line_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y + GetHandleSize() * z); + cairo_line_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y - GetHandleSize() * z); cairo_stroke(cr); } } @@ -282,6 +298,11 @@ tool_ = Tool_Crop; break; + case 'm': + tool_ = Tool_Mask; + widget.Select(1); + break; + case 'd': { // dump to json and reload @@ -340,7 +361,7 @@ widget.SwitchInvert(); break; - case 'm': + case 't': tool_ = Tool_Move; break; @@ -409,6 +430,7 @@ boost::shared_ptr<RadiographyScene> scene_; RadiographyEditorInteractor interactor_; Orthanc::FontRegistry fontRegistry_; + RadiographyMaskLayer* maskLayer_; public: SingleFrameEditorApplication(MessageBroker& broker) : @@ -449,10 +471,11 @@ statusBar.SetMessage("Use the key \"e\" to export DICOM to the Orthanc server"); statusBar.SetMessage("Use the key \"f\" to switch full screen"); statusBar.SetMessage("Use the key \"i\" to invert contrast"); - statusBar.SetMessage("Use the key \"m\" to move objects"); + statusBar.SetMessage("Use the key \"m\" to modify the mask"); statusBar.SetMessage("Use the key \"n\" to switch between nearest neighbor and bilinear interpolation"); statusBar.SetMessage("Use the key \"r\" to rotate objects"); statusBar.SetMessage("Use the key \"s\" to resize objects (not applicable to DICOM layers)"); + statusBar.SetMessage("Use the key \"t\" to move (translate) objects"); statusBar.SetMessage("Use the key \"w\" to change windowing"); statusBar.SetMessage("Use the key \"ctrl-z\" to undo action"); @@ -480,10 +503,13 @@ //scene_->LoadDicomWebFrame(context->GetWebService()); std::vector<MaskPoint> mask; - mask.push_back(MaskPoint(100, 100)); - mask.push_back(MaskPoint(100, 1000)); - mask.push_back(MaskPoint(1000, 1000)); - scene_->LoadMask(mask, dynamic_cast<RadiographyDicomLayer&>(dicomLayer), 128.0f, NULL); + mask.push_back(MaskPoint(1100, 100)); + mask.push_back(MaskPoint(1100, 1000)); + mask.push_back(MaskPoint(2000, 1000)); + mask.push_back(MaskPoint(2200, 150)); + mask.push_back(MaskPoint(1500, 550)); + maskLayer_ = dynamic_cast<RadiographyMaskLayer*>(&(scene_->LoadMask(mask, dynamic_cast<RadiographyDicomLayer&>(dicomLayer), 128.0f, NULL))); + interactor_.SetMaskLayer(maskLayer_); { RadiographyLayer& layer = scene_->LoadText(fontRegistry_.GetFont(0), "Hello\nworld", NULL);
--- a/Framework/Radiography/RadiographyLayer.cpp Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/Radiography/RadiographyLayer.cpp Wed Feb 13 12:04:02 2019 +0100 @@ -76,58 +76,14 @@ double x, double y) const { - transform_.Apply(x, y); + GetTransform().Apply(x, y); extent.AddPoint(x, y); } - - void RadiographyLayer::GetCornerInternal(double& x, - double& y, - Corner corner, - unsigned int cropX, - unsigned int cropY, - unsigned int cropWidth, - unsigned int cropHeight) const - { - double dx = static_cast<double>(cropX); - double dy = static_cast<double>(cropY); - double dwidth = static_cast<double>(cropWidth); - double dheight = static_cast<double>(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); - } - - transform_.Apply(x, y); - } - - bool RadiographyLayer::Contains(double x, double y) const { - transformInverse_.Apply(x, y); + GetTransformInverse().Apply(x, y); unsigned int cropX, cropY, cropWidth, cropHeight; GetCrop(cropX, cropY, cropWidth, cropHeight); @@ -140,43 +96,23 @@ void RadiographyLayer::DrawBorders(CairoContext& context, double zoom) { - unsigned int cx, cy, width, height; - GetCrop(cx, cy, width, height); - - double dx = static_cast<double>(cx); - double dy = static_cast<double>(cy); - double dwidth = static_cast<double>(width); - double dheight = static_cast<double>(height); + if (GetControlPointCount() < 3 ) + return; cairo_t* cr = context.GetObject(); cairo_set_line_width(cr, 2.0 / zoom); - double x, y; - x = dx; - y = dy; - transform_.Apply(x, y); - cairo_move_to(cr, x, y); - - x = dx + dwidth; - y = dy; - transform_.Apply(x, y); - cairo_line_to(cr, x, y); + ControlPoint cp; + GetControlPoint(cp, 0); + cairo_move_to(cr, cp.x, cp.y); - x = dx + dwidth; - y = dy + dheight; - transform_.Apply(x, y); - cairo_line_to(cr, x, y); + for (size_t i = 0; i < GetControlPointCount(); i++) + { + GetControlPoint(cp, i); + cairo_line_to(cr, cp.x, cp.y); + } - x = dx; - y = dy + dheight; - transform_.Apply(x, y); - cairo_line_to(cr, x, y); - - x = dx; - y = dy; - transform_.Apply(x, y); - cairo_line_to(cr, x, y); - + cairo_close_path(cr); cairo_stroke(cr); } @@ -237,7 +173,7 @@ { GetGeometry().GetCrop(x, y, width, height); } - else + else { x = 0; y = 0; @@ -305,7 +241,7 @@ } else { - transformInverse_.Apply(sceneX, sceneY); + GetTransformInverse().Apply(sceneX, sceneY); int x = static_cast<int>(std::floor(sceneX)); int y = static_cast<int>(std::floor(sceneY)); @@ -362,48 +298,71 @@ { centerX = static_cast<double>(width_) / 2.0; centerY = static_cast<double>(height_) / 2.0; - transform_.Apply(centerX, centerY); - } - - - void RadiographyLayer::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); + GetTransform().Apply(centerX, centerY); } - bool RadiographyLayer::LookupCorner(Corner& corner /* out */, - double x, - double y, - double zoom, - double viewportDistance) const + + size_t RadiographyLayer::GetControlPointCount() const {return 4;} + + void RadiographyLayer::GetControlPointInternal(ControlPoint& controlPoint, + size_t index) const { - static const Corner CORNERS[] = { - Corner_TopLeft, - Corner_TopRight, - Corner_BottomLeft, - Corner_BottomRight - }; - unsigned int cropX, cropY, cropWidth, cropHeight; GetCrop(cropX, cropY, cropWidth, cropHeight); + switch (index) + { + case ControlPoint_TopLeftCorner: + controlPoint = ControlPoint(cropX, cropY, ControlPoint_TopLeftCorner); + break; + + case ControlPoint_TopRightCorner: + controlPoint = ControlPoint(cropX + cropWidth, cropY, ControlPoint_TopRightCorner); + break; + + case ControlPoint_BottomLeftCorner: + controlPoint = ControlPoint(cropX, cropY + cropHeight, ControlPoint_BottomLeftCorner); + break; + + case ControlPoint_BottomRightCorner: + controlPoint = ControlPoint(cropX + cropWidth, cropY + cropHeight, ControlPoint_BottomRightCorner); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + } + + + + void RadiographyLayer::GetControlPoint(ControlPoint& controlPoint /* out */, + size_t index) const + { + GetControlPointInternal(controlPoint, index); + GetTransform().Apply(controlPoint.x, controlPoint.y); + } + + + bool RadiographyLayer::LookupControlPoint(ControlPoint& controlPoint /* out */, + double x, + double y, + double zoom, + double viewportDistance) const + { double threshold = Square(viewportDistance / zoom); - for (size_t i = 0; i < 4; i++) + for (size_t i = 0; i < GetControlPointCount(); i++) { - double cx, cy; - GetCornerInternal(cx, cy, CORNERS[i], cropX, cropY, cropWidth, cropHeight); + ControlPoint cp; + GetControlPoint(cp, i); - double d = Square(cx - x) + Square(cy - y); + double d = Square(cp.x - x) + Square(cp.y - y); if (d <= threshold) { - corner = CORNERS[i]; + controlPoint = cp; return true; } }
--- a/Framework/Radiography/RadiographyLayer.h Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/Radiography/RadiographyLayer.h Wed Feb 13 12:04:02 2019 +0100 @@ -27,6 +27,25 @@ namespace OrthancStone { + struct ControlPoint + { + double x; + double y; + size_t index; + + ControlPoint(double x, double y, size_t index) + : x(x), + y(y), + index(index) + {} + + ControlPoint() + : x(0), + y(0), + index(std::numeric_limits<size_t>::max()) + {} + }; + class RadiographyLayer : public boost::noncopyable { friend class RadiographyScene; @@ -144,39 +163,39 @@ protected: - const AffineTransform2D& GetTransform() const + virtual const AffineTransform2D& GetTransform() const { return transform_; } + virtual const AffineTransform2D& GetTransformInverse() const + { + return transformInverse_; + } + void SetPreferredPhotomotricDisplayMode(PhotometricDisplayMode prefferedPhotometricDisplayMode) { prefferedPhotometricDisplayMode_ = prefferedPhotometricDisplayMode; } + virtual void GetControlPointInternal(ControlPoint& controlPoint, + size_t index) const; + private: void UpdateTransform(); - + void AddToExtent(Extent2D& extent, double x, double y) const; - void GetCornerInternal(double& x, - double& y, - Corner corner, - unsigned int cropX, - unsigned int cropY, - unsigned int cropWidth, - unsigned int cropHeight) const; - void SetIndex(size_t index) { index_ = index; } - + bool Contains(double x, double y) const; - + void DrawBorders(CairoContext& context, double zoom); @@ -232,12 +251,12 @@ unsigned int GetWidth() const { return width_; - } + } unsigned int GetHeight() const { return height_; - } + } Extent2D GetExtent() const; @@ -252,15 +271,16 @@ void GetCenter(double& centerX, double& centerY) const; - void GetCorner(double& x /* out */, - double& y /* out */, - Corner corner) const; - - bool LookupCorner(Corner& corner /* out */, - double x, - double y, - double zoom, - double viewportDistance) const; + void GetControlPoint(ControlPoint& controlPoint, + size_t index) const; + + virtual size_t GetControlPointCount() const; + + bool LookupControlPoint(ControlPoint& controlPoint /* out */, + double x, + double y, + double zoom, + double viewportDistance) const; virtual bool GetDefaultWindowing(float& center, float& width) const = 0;
--- a/Framework/Radiography/RadiographyLayerCropTracker.cpp Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/Radiography/RadiographyLayerCropTracker.cpp Wed Feb 13 12:04:02 2019 +0100 @@ -68,12 +68,10 @@ RadiographyScene& scene, const ViewportGeometry& view, size_t layer, - double x, - double y, - Corner corner) : + const ControlPoint& startControlPoint) : undoRedoStack_(undoRedoStack), accessor_(scene, layer), - corner_(corner) + startControlPoint_(startControlPoint) { if (accessor_.IsValid()) { @@ -114,8 +112,8 @@ { unsigned int targetX, targetWidth; - if (corner_ == Corner_TopLeft || - corner_ == Corner_BottomLeft) + if (startControlPoint_.index == ControlPoint_TopLeftCorner || + startControlPoint_.index == ControlPoint_BottomLeftCorner) { targetX = std::min(x, cropX_ + cropWidth_); targetWidth = cropX_ + cropWidth_ - targetX; @@ -128,8 +126,8 @@ unsigned int targetY, targetHeight; - if (corner_ == Corner_TopLeft || - corner_ == Corner_TopRight) + if (startControlPoint_.index == ControlPoint_TopLeftCorner || + startControlPoint_.index == ControlPoint_TopRightCorner) { targetY = std::min(y, cropY_ + cropHeight_); targetHeight = cropY_ + cropHeight_ - targetY;
--- a/Framework/Radiography/RadiographyLayerCropTracker.h Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/Radiography/RadiographyLayerCropTracker.h Wed Feb 13 12:04:02 2019 +0100 @@ -35,7 +35,7 @@ UndoRedoStack& undoRedoStack_; RadiographyScene::LayerAccessor accessor_; - Corner corner_; + ControlPoint startControlPoint_; unsigned int cropX_; unsigned int cropY_; unsigned int cropWidth_; @@ -46,9 +46,7 @@ RadiographyScene& scene, const ViewportGeometry& view, size_t layer, - double x, - double y, - Corner corner); + const ControlPoint& startControlPoint); virtual bool HasRender() const {
--- a/Framework/Radiography/RadiographyLayerResizeTracker.cpp Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/Radiography/RadiographyLayerResizeTracker.cpp Wed Feb 13 12:04:02 2019 +0100 @@ -85,9 +85,7 @@ RadiographyLayerResizeTracker::RadiographyLayerResizeTracker(UndoRedoStack& undoRedoStack, RadiographyScene& scene, size_t layer, - double x, - double y, - Corner corner, + const ControlPoint& startControlPoint, bool roundScaling) : undoRedoStack_(undoRedoStack), accessor_(scene, layer), @@ -101,31 +99,32 @@ originalPanX_ = accessor_.GetLayer().GetGeometry().GetPanX(); originalPanY_ = accessor_.GetLayer().GetGeometry().GetPanY(); - switch (corner) + size_t oppositeControlPointType; + switch (startControlPoint.index) { - case Corner_TopLeft: - oppositeCorner_ = Corner_BottomRight; + case ControlPoint_TopLeftCorner: + oppositeControlPointType = ControlPoint_BottomRightCorner; break; - case Corner_TopRight: - oppositeCorner_ = Corner_BottomLeft; + case ControlPoint_TopRightCorner: + oppositeControlPointType = ControlPoint_BottomLeftCorner; break; - case Corner_BottomLeft: - oppositeCorner_ = Corner_TopRight; + case ControlPoint_BottomLeftCorner: + oppositeControlPointType = ControlPoint_TopRightCorner; break; - case Corner_BottomRight: - oppositeCorner_ = Corner_TopLeft; + case ControlPoint_BottomRightCorner: + oppositeControlPointType = ControlPoint_TopLeftCorner; break; default: throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } - accessor_.GetLayer().GetCorner(oppositeX_, oppositeY_, oppositeCorner_); + accessor_.GetLayer().GetControlPoint(startOppositeControlPoint_, oppositeControlPointType); - double d = ComputeDistance(x, y, oppositeX_, oppositeY_); + double d = ComputeDistance(startControlPoint.x, startControlPoint.y, startOppositeControlPoint_.x, startOppositeControlPoint_.y); if (d >= std::numeric_limits<float>::epsilon()) { baseScaling_ = 1.0 / d; @@ -168,7 +167,7 @@ if (accessor_.IsValid() && accessor_.GetLayer().GetGeometry().IsResizeable()) { - double scaling = ComputeDistance(oppositeX_, oppositeY_, sceneX, sceneY) * baseScaling_; + double scaling = ComputeDistance(startOppositeControlPoint_.x, startOppositeControlPoint_.y, sceneX, sceneY) * baseScaling_; if (roundScaling_) { @@ -180,10 +179,10 @@ scaling * originalSpacingY_); // Keep the opposite corner at a fixed location - double ox, oy; - layer.GetCorner(ox, oy, oppositeCorner_); - layer.SetPan(layer.GetGeometry().GetPanX() + oppositeX_ - ox, - layer.GetGeometry().GetPanY() + oppositeY_ - oy); + ControlPoint currentOppositeCorner; + layer.GetControlPoint(currentOppositeCorner, startOppositeControlPoint_.index); + layer.SetPan(layer.GetGeometry().GetPanX() + startOppositeControlPoint_.x - currentOppositeCorner.x, + layer.GetGeometry().GetPanY() + startOppositeControlPoint_.y - currentOppositeCorner.y); } } }
--- a/Framework/Radiography/RadiographyLayerResizeTracker.h Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/Radiography/RadiographyLayerResizeTracker.h Wed Feb 13 12:04:02 2019 +0100 @@ -39,18 +39,14 @@ double originalSpacingY_; double originalPanX_; double originalPanY_; - Corner oppositeCorner_; - double oppositeX_; - double oppositeY_; + ControlPoint startOppositeControlPoint_; double baseScaling_; public: RadiographyLayerResizeTracker(UndoRedoStack& undoRedoStack, RadiographyScene& scene, size_t layer, - double x, - double y, - Corner corner, + const ControlPoint& startControlPoint, bool roundScaling); virtual bool HasRender() const
--- a/Framework/Radiography/RadiographyMaskLayer.cpp Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/Radiography/RadiographyMaskLayer.cpp Wed Feb 13 12:04:02 2019 +0100 @@ -29,6 +29,18 @@ namespace OrthancStone { + const unsigned char IN_MASK_VALUE = 0x00; + const unsigned char OUT_MASK_VALUE = 0xFF; + + const AffineTransform2D& RadiographyMaskLayer::GetTransform() const + { + return dicomLayer_.GetTransform(); + } + + const AffineTransform2D& RadiographyMaskLayer::GetTransformInverse() const + { + return dicomLayer_.GetTransformInverse(); + } void ComputeMaskExtent(unsigned int& left, unsigned int& right, unsigned int& top, unsigned int& bottom, const std::vector<MaskPoint>& corners) { @@ -66,18 +78,6 @@ DrawMask(); -// for (unsigned int i = 0; i < 100; i++) -// { -// for (unsigned int j = 0; j < 50; j++) -// { -// if ((i + j) % 2 == 1) -// { -// Orthanc::ImageAccessor region; -// mask_->GetRegion(region, i* 20, j * 20, 20, 20); -// Orthanc::ImageProcessing::Set(region, 255); -// } -// } -// } invalidated_ = false; } @@ -112,7 +112,7 @@ for (unsigned int x = 0; x < width; x++, p++, q++) { - if (*p == 0) + if (*p == OUT_MASK_VALUE) *q = foreground_; // else keep the underlying pixel value } @@ -214,6 +214,36 @@ return count&1; // Same as (count%2 == 1) } + void RadiographyMaskLayer::DrawLine(const MaskPoint& start, const MaskPoint& end) const + { + int dx = (int)(end.x) - (int)(start.x); + int dy = (int)(end.y) - (int)(start.y); + + if (std::abs(dx) > std::abs(dy)) + { // the line is closer to horizontal + + int incx = dx / std::abs(dx); + double incy = (double)(dy)/(double)(dx); + double y = (double)(start.y); + for (int x = (int)(start.x); x != (int)(end.x); x += incx, y += incy) + { + unsigned char* p = reinterpret_cast<unsigned char*>(mask_->GetRow((int)(y + 0.5))) + x; + *p = IN_MASK_VALUE; + } + } + else + { // the line is closer to vertical + int incy = dy / std::abs(dy); + double incx = (double)(dx)/(double)(dy); + double x = (double)(start.x); + for (int y = (int)(start.y); y != (int)(end.y); y += incy, x += incx) + { + unsigned char* p = reinterpret_cast<unsigned char*>(mask_->GetRow(y)) + (int)(x + 0.5); + *p = IN_MASK_VALUE; + } + } + } + void RadiographyMaskLayer::DrawMask() const { @@ -222,26 +252,114 @@ unsigned int top; unsigned int bottom; - ComputeMaskExtent(left, right, top, bottom, corners_); +// ComputeMaskExtent(left, right, top, bottom, corners_); - Orthanc::ImageProcessing::Set(*mask_, 0); + left = 0; + right = 2500; + top = 0; + bottom = 2500; + // first fill the complete image + Orthanc::ImageProcessing::Set(*mask_, OUT_MASK_VALUE); - MaskPoint p(left, top); - for (p.y = top; p.y <= bottom; p.y++) + { - unsigned char* q = reinterpret_cast<unsigned char*>(mask_->GetRow(p.y)); - for (p.x = left; p.x <= right; p.x++, q++) + // from http://alienryderflex.com/polygon_fill/ + std::auto_ptr<int> raiiNodeX(new int(corners_.size())); + + std::vector<int> nodeX; + nodeX.resize(corners_.size()); + int nodes, pixelX, pixelY, i, j, swap ; + + // Loop through the rows of the image. + for (pixelY = (int)top; pixelY < (int)bottom; pixelY++) { - if (isInside(corners_, p)) + // Build a list of nodes. + nodes = 0; + j = (int)corners_.size() - 1; + + for (i = 0; i < (int)corners_.size(); i++) + { + if ((int)corners_[i].y < pixelY && (int)corners_[j].y >= pixelY + || (int)corners_[j].y < pixelY && (int)corners_[i].y >= pixelY) + { + nodeX[nodes++]= (int)((double)corners_[i].x + ((double)pixelY - (double)corners_[i].y)/((double)corners_[j].y - (double)corners_[i].y) *((double)corners_[j].x - (double)corners_[i].x)); + } + j=i; + } + + // Sort the nodes, via a simple “Bubble” sort. + i=0; + while (i<nodes-1) { - *q = 255; + if (nodeX[i]>nodeX[i+1]) + { + swap=nodeX[i]; nodeX[i]=nodeX[i+1]; nodeX[i+1]=swap; if (i) i--; + } + else + { + i++; + } + } + + unsigned char* row = reinterpret_cast<unsigned char*>(mask_->GetRow(pixelY)); + // Fill the pixels between node pairs. + for (i=0; i<nodes; i+=2) + { + if (nodeX[i ]>=(int)right) + break; + if (nodeX[i+1]> (int)left) + { + if (nodeX[i ]< (int)left ) + nodeX[i ]=(int)left ; + if (nodeX[i+1]> (int)right) + nodeX[i+1]=(int)right; + for (pixelX=nodeX[i]; pixelX<nodeX[i+1]; pixelX++) + { + *(row + pixelX) = IN_MASK_VALUE; + } + } } } } -// Orthanc::ImageAccessor region; -// mask_->GetRegion(region, 100, 100, 1000, 1000); -// Orthanc::ImageProcessing::Set(region, 255); +// // draw lines +// for (size_t i = 1; i < corners_.size(); i++) +// { +// DrawLine(corners_[i-1], corners_[i]); +// } +// DrawLine(corners_[corners_.size()-1], corners_[0]); + +// // fill between lines +// MaskPoint p(left, top); +// for (p.y = top; p.y <= bottom; p.y++) +// { +// unsigned char* q = reinterpret_cast<unsigned char*>(mask_->GetRow(p.y)) + left; +// unsigned char previousPixelValue1 = OUT_MASK_VALUE; +// unsigned char previousPixelValue2 = OUT_MASK_VALUE; +// for (p.x = left; p.x <= right; p.x++, q++) +// { +// if (*p == OUT_MASK_VALUE && previousPixelValue1 == IN_MASK_VALUE && previousPixelValue2 == OUT_MASK_VALUE) // we just passed over a single one pixel line => start filling +// { + +// *q = IN_MASK_VALUE; +// } +// } +// } + + +// MaskPoint p(left, top); +// for (p.y = top; p.y <= bottom; p.y++) +// { +// unsigned char* q = reinterpret_cast<unsigned char*>(mask_->GetRow(p.y)) + left; +// for (p.x = left; p.x <= right; p.x++, q++) +// { +// if (isInside(corners_, p)) +// { +// *q = IN_MASK_VALUE; +// } +// } +// } + } }
--- a/Framework/Radiography/RadiographyMaskLayer.h Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/Radiography/RadiographyMaskLayer.h Wed Feb 13 12:04:02 2019 +0100 @@ -65,6 +65,17 @@ const AffineTransform2D& viewTransform, ImageInterpolation interpolation) const; + virtual size_t GetControlPointCount() const + { + return corners_.size(); + } + + virtual void GetControlPointInternal(ControlPoint& controlPoint, + size_t index) const + { + controlPoint = ControlPoint(corners_[index].x, corners_[index].y, index); + } + virtual bool GetDefaultWindowing(float& center, float& width) const { @@ -91,7 +102,15 @@ } + protected: + virtual const AffineTransform2D& GetTransform() const; + + virtual const AffineTransform2D& GetTransformInverse() const; + + private: void DrawMask() const; + void DrawLine(const MaskPoint& start, const MaskPoint& end) const; + }; }
--- a/Framework/StoneEnumerations.h Tue Feb 12 12:22:13 2019 +0100 +++ b/Framework/StoneEnumerations.h Wed Feb 13 12:04:02 2019 +0100 @@ -172,12 +172,12 @@ }; - enum Corner + enum ControlPointType { - Corner_TopLeft, - Corner_TopRight, - Corner_BottomLeft, - Corner_BottomRight + ControlPoint_TopLeftCorner = 0, + ControlPoint_TopRightCorner = 1, + ControlPoint_BottomRightCorner = 2, + ControlPoint_BottomLeftCorner = 3 }; enum PhotometricDisplayMode