MeshLib
 
Loading...
Searching...
No Matches
MRObjectTransformWidget.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRViewer.h"
6#include "MRMesh/MRMeshFwd.h"
7#include "MRMesh/MRVector3.h"
10#include "MRMesh/MRAxis.h"
11#include <MRMesh/MRObject.h>
12#include <MRMesh/MRColor.h>
13#include "MRMesh/MRSignal.h"
14#include <array>
15#include <functional>
16#include <string>
17
18namespace MR
19{
20
21enum class ControlBit
22{
23 None = 0,
24 RotX = 0x1,
25 RotY = 0x2,
26 RotZ = 0x4,
27 RotMask = RotX | RotY | RotZ,
28 MoveX = 0x8,
29 MoveY = 0x10,
30 MoveZ = 0x20,
33};
35
36// This lambda is called in each frame, and returns transform mode mask for this frame in given viewport
37// if not set, full mask is return
38using TransformModesValidator = std::function<ControlBit( const Vector3f& center, const AffineXf3f& xf, ViewportId )>;
39
40
41// Interface class for ObjectTransformWidget custom visualization
42class MRVIEWER_CLASS ITransformControls
43{
44public:
45 virtual ~ITransformControls() = default;
46
47 // get center of the widget in local space
48 const Vector3f& getCenter() const { return center_; }
49 MRVIEWER_API void setCenter( const Vector3f& center );
50
51 // should return current radius of the widget
52 virtual float getRadius() const { return 1.0f; }
53
54 // This lambda is called in each frame, and returns transform mode mask for this frame in given viewport
55 // if not set, full mask is return
56 void setTransformModesValidator( TransformModesValidator validator ) { validator_ = validator; }
57
58 // Enables or disables pick through mode, in this mode controls will be picked even if they are occluded by other objects
59 void setPickThrough( bool on ) { pickThrough_ = on; }
60 bool getPickThrough() const { return pickThrough_; }
61
62 // Returns currently hovered control
63 ControlBit getHoveredControl() const { return hoveredControl_; }
64
65 // Called once on widget created to init internal objects
66 virtual void init( std::shared_ptr<Object> parent ) = 0;
67 // Called right after init and can be called on some internal actions to recreate
68 // objects visualization
69 virtual void update() = 0;
70 // Called for hover checks
71 void hover() { hoveredControl_ = hover_( pickThrough_ ); }
72 // This is called to stop drawing active visualization when modification is stopped
73 void stopModify() { stopModify_(); hover(); }
74
75 // Called each frame for each viewport to update available transformation modes
76 MRVIEWER_API void updateVisualTransformMode( ControlBit showMask, ViewportMask viewportMask, const AffineXf3f& xf );
77
78 // One have to implement these functions to have visualization of translation and rotation
79 virtual void updateTranslation( Axis ax, const Vector3f& startMove, const Vector3f& endMove ) = 0;
80 // xf - widget current xf
81 virtual void updateRotation( Axis ax, const AffineXf3f& xf, float startAngle, float endAngle ) = 0;
82
83 // build-in history action class for change center
85 {
86 public:
87 ChangeCenterAction( const std::string& name, ITransformControls& controls ) :
88 controls_{ controls },
89 name_{ name }{ center_ = controls.getCenter(); }
90
91 virtual std::string name() const override { return name_; }
92
93 virtual void action( HistoryAction::Type ) override
94 {
95 auto center = controls_.getCenter();
96 controls_.setCenter( center_ );
97 center_ = center;
98 }
99
100 [[nodiscard]] virtual size_t heapBytes() const override { return name_.capacity(); }
101
102 private:
103 ITransformControls& controls_;
104 Vector3f center_;
105 std::string name_;
106 };
107protected:
108 // one have to implement this function
109 // it can change internal visualization and return currently hovered control
110 virtual ControlBit hover_( bool pickThrough ) = 0;
111 // one have to implement this function
112 // it can change internal visualization
113 // called when modification is stopped
114 virtual void stopModify_() = 0;
115 // one have to implement this function
116 // it can be called in each frame (each viewport if needed) to update transform mode in different viewports
117 virtual void updateVisualTransformMode_( ControlBit showMask, ViewportMask viewportMask ) = 0;
118private:
119 Vector3f center_;
120
121 ControlBit hoveredControl_{ ControlBit::None };
122 bool pickThrough_{ false };
123 TransformModesValidator validator_;
124};
125
126// Basic implementation of ITransformControls
127class MRVIEWER_CLASS TransformControls : public ITransformControls
128{
129public:
130 struct MRVIEWER_CLASS VisualParams
131 {
132 // updates radius and width with given box
133 MRVIEWER_API void update( const Box3f& box );
134 float radius{ -1.0f };
135 float width{ -1.0f };
137 float coneRadiusFactor{ 1.35f };
139 float coneSizeFactor{ 2.2f };
141 float negativeLineExtension{ 1.15f };
143 float positiveLineExtension{ 1.3f };
145 std::array<Color, size_t( Axis::Count )> rotationColors{ Color::red(),Color::green(),Color::blue() };
146 std::array<Color, size_t( Axis::Count )> translationColors{ Color::red(),Color::green(),Color::blue() };
147 Color helperLineColor{ Color::black() };
148 Color activeLineColor{ Color::white() };
149 };
150 MRVIEWER_API void setVisualParams( const VisualParams& params );
151 const VisualParams& getVisualParams() const { return params_; }
152
153 MRVIEWER_API virtual ~TransformControls();
154
155 MRVIEWER_API virtual void init( std::shared_ptr<Object> parent ) override;
156 MRVIEWER_API virtual void update() override;
157
158 virtual float getRadius() const override { return params_.radius; }
159 // get current width of widget controls
160 // negative value means that controls are not setup
161 float getWidth() const { return params_.width; }
162 // set width for this widget
163 MRVIEWER_API void setWidth( float width );
164
165 MRVIEWER_API virtual void updateTranslation( Axis ax, const Vector3f& startMove, const Vector3f& endMove ) override;
166 MRVIEWER_API virtual void updateRotation( Axis ax, const AffineXf3f& xf, float startAngle, float endAngle ) override;
167
168 // returns TransformModesValidator by threshold dot value (this value is duty for hiding widget controls that have small projection on screen)
169 MRVIEWER_API static TransformModesValidator ThresholdDotValidator( float thresholdDot );
170private:
171 MRVIEWER_API virtual ControlBit hover_( bool pickThrough ) override;
172 MRVIEWER_API virtual void stopModify_() override;
173 MRVIEWER_API virtual void updateVisualTransformMode_( ControlBit showMask, ViewportMask viewportMask ) override;
174
175 VisualParams params_;
176
177 // Control objects
178 std::array<std::shared_ptr<ObjectMesh>, size_t( Axis::Count )> translateControls_;
179 std::array<std::shared_ptr<ObjectMesh>, size_t( Axis::Count )> rotateControls_;
180
181 // if active line is visible, other lines are not
182 std::shared_ptr<ObjectLines> activeLine_;
183 std::array<std::shared_ptr<ObjectLines>, size_t( Axis::Count )> translateLines_;
184 std::array<std::shared_ptr<ObjectLines>, size_t( Axis::Count )> rotateLines_;
185
186 std::shared_ptr<ObjectMesh> hoveredObject_;
187 int findHoveredIndex_() const;
188 void setActiveLineFromPoints_( const Contour3f& points );
189};
190
191// Visual widget to modify transform
192// present in scene (ancillary), subscribes to viewer events
193class MRVIEWER_CLASS ObjectTransformWidget : public MultiListener<MouseDownListener, MouseMoveListener, MouseUpListener, PreDrawListener, PostDrawListener>
194{
195public:
196 // Creates transform widget around given box and applies given xf
197 // subscribes to viewer events
198 // controls: class that is responsible for visualization
199 // if controls is empty default TransformControls is used
200 MRVIEWER_API void create( const Box3f& box, const AffineXf3f& xf, std::shared_ptr<ITransformControls> controls = {} );
201 // Removes widget from scene and clears all widget objects
202 // unsubscribes from viewer events
203 MRVIEWER_API void reset();
204
205 // Returns current transform mode mask
206 ControlBit getTransformModeMask( ViewportId id = {} ) const { return transformModeMask_.get( id ); }
207 // Sets transform mode mask (enabling or disabling corresponding widget controls)
208 MRVIEWER_API void setTransformMode( ControlBit mask, ViewportId id = {} );
209
210 // Transform operation applying to object while dragging an axis. This parameter does not apply to active operation.
212 {
213 // object moves along an axis
215 // object inflates or deflates along an axis depending on drag direction (away from center or toward center respectively)
217 // object inflates or deflates along all axes depending on drag direction (away from center or toward center respectively)
219 };
220 // Returns current axis transform mode (translate/scale object while dragging an axis)
221 AxisTransformMode getAxisTransformMode() const { return axisTransformMode_; };
222 // Sets current axis transform mode (translate/scale object while dragging an axis)
223 void setAxisTransformMode( AxisTransformMode mode ) { axisTransformMode_ = mode; };
224
225 // Returns root object of widget
226 std::shared_ptr<Object> getRootObject() const { return controlsRoot_; }
227
228 // Returns controls object, that visualize widget
229 std::shared_ptr<ITransformControls> getControls() const { return controls_; }
230 template<typename T>
231 std::shared_ptr<T> getControlsAs() const { return std::dynamic_pointer_cast< T >( controls_ ); }
232
233 // Changes controls xf (controls will affect object in basis of new xf)
234 // note that rotation is applied around 0 coordinate in world space, so use xfAround to process rotation around user defined center
235 // non-uniform scale will be converted to uniform one based on initial box diagonal
236 MRVIEWER_API void setControlsXf( const AffineXf3f& xf, ViewportId id = {} );
237 MRVIEWER_API AffineXf3f getControlsXf( ViewportId id = {} ) const;
238
239 // Subscribes to object visibility, and behave like its child
240 // if obj argument is null, stop following
241 MRVIEWER_API void followObjVisibility( const std::weak_ptr<Object>& obj );
242
243 // Sets callback that will be called in draw function during scaling with current scale arg
244 void setScaleTooltipCallback( std::function<void( float )> callback ) { scaleTooltipCallback_ = callback; }
245 // Sets callback that will be called in draw function during translation with current shift arg
246 void setTranslateTooltipCallback( std::function<void( float )> callback ) { translateTooltipCallback_ = callback; }
247 // Sets callback that will be called in draw function during rotation with current angle in rad
248 void setRotateTooltipCallback( std::function<void( float )> callback ) { rotateTooltipCallback_ = callback; }
249
250 // Sets callback that will be called when modification of widget stops
251 void setStopModifyCallback( std::function<void()> callback ) { stopModifyCallback_ = callback; }
252 // Sets callback that will be called when modification of widget starts
253 void setStartModifyCallback( std::function<void()> callback ) { startModifyCallback_ = callback; }
254 // Sets callback that will be called when widget gets additive transform
255 void setAddXfCallback( std::function<void( const AffineXf3f& )> callback ) { addXfCallback_ = callback; }
256 // Sets callback that will be called when widget gets additive transform
257 // The callback should return true to approve transform and false to reject it
258 void setApproveXfCallback( std::function<bool( const AffineXf3f& )> callback ) { approveXfCallback_ = callback; }
259
260 // History action for TransformWidget
262 {
263 public:
264 ChangeXfAction( const std::string& name, ObjectTransformWidget& widget ) :
265 widget_{ widget },
266 name_{ name }
267 {
268 if ( widget_.controlsRoot_ )
269 {
270 xf_ = widget_.controlsRoot_->xfsForAllViewports();
271 scaledXf_ = widget_.scaledXf_;
272 }
273 }
274
275 virtual std::string name() const override
276 {
277 return name_;
278 }
279
280 virtual void action( HistoryAction::Type ) override
281 {
282 if ( !widget_.controlsRoot_ )
283 return;
284 auto tmpXf = widget_.controlsRoot_->xfsForAllViewports();
285 widget_.controlsRoot_->setXfsForAllViewports( xf_ );
286 xf_ = tmpXf;
287
288 std::swap( scaledXf_, widget_.scaledXf_ );
289 }
290
291 [[nodiscard]] virtual size_t heapBytes() const override
292 {
293 return name_.capacity();
294 }
295
296 private:
297 ObjectTransformWidget& widget_;
300 std::string name_;
301 };
302private:
303 MRVIEWER_API virtual bool onMouseDown_( Viewer::MouseButton button, int modifier ) override;
304 MRVIEWER_API virtual bool onMouseUp_( Viewer::MouseButton button, int modifier ) override;
305 MRVIEWER_API virtual bool onMouseMove_( int mouse_x, int mouse_y ) override;
306 MRVIEWER_API virtual void preDraw_() override;
307 MRVIEWER_API virtual void postDraw_() override;
308
309 void activeMove_( bool press = false );
310
311 void processScaling_( Axis ax, bool press );
312 void processTranslation_( Axis ax, bool press );
313 void processRotation_( Axis ax, bool press );
314
315 void setControlsXf_( const AffineXf3f& xf, bool updateScaled, ViewportId id = {} );
316
317 std::weak_ptr<Object> visibilityParent_;
318
319 // undiformAddXf - for ActiveEditMode::ScalingMode only, to scale widget uniformly
320 void addXf_( const AffineXf3f& addXf );
321 void stopModify_();
322
323 // main object that holds all other controls
324 std::shared_ptr<Object> controlsRoot_;
325 std::shared_ptr<ITransformControls> controls_;
326
327 AxisTransformMode axisTransformMode_{ AxisTranslation };
328
329 enum ActiveEditMode
330 {
331 TranslationMode,
332 ScalingMode,
333 UniformScalingMode,
334 RotationMode,
335 };
336 ActiveEditMode activeEditMode_{ TranslationMode };
337
338 // Initial box diagonal vector (before transformation),
339 // it is needed to correctly convert non-uniform scaling to uniform one and apply it to this widget
340 Vector3f boxDiagonal_;
341 // same as controlsRoot_->xf() but with non uniform scaling applied
342 ViewportProperty<AffineXf3f> scaledXf_;
343 // this is needed for tooltip only
344 float currentScaling_ = 1.0f;
345
346 Vector3f prevScaling_;
347 Vector3f startTranslation_;
348 Vector3f prevTranslation_;
349 float accumShift_ = 0;
350
351 float startAngle_ = 0;
352 float accumAngle_ = 0;
353
354 ViewportProperty<ControlBit> transformModeMask_{ ControlBit::FullMask };
355 bool picked_{ false };
356
357 std::function<void( float )> scaleTooltipCallback_;
358 std::function<void( float )> translateTooltipCallback_;
359 std::function<void( float )> rotateTooltipCallback_;
360
361 std::function<void()> startModifyCallback_;
362 std::function<void()> stopModifyCallback_;
363 std::function<void( const AffineXf3f& )> addXfCallback_;
364 std::function<bool( const AffineXf3f& )> approveXfCallback_;
365 bool approvedChange_ = true; // if controlsRoot_ xf changed without approve, user modification stops
366 boost::signals2::connection xfValidatorConnection_;
367};
368
369}
#define MR_MAKE_FLAG_OPERATORS(T)
Definition MRFlagOperators.h:6
affine transformation: y = A*x + b, where A in VxV, and b in V
Definition MRDotNet/MRAffineXf.h:8
Definition MRHistoryAction.h:12
Type
Definition MRHistoryAction.h:19
Definition MRObjectTransformWidget.h:85
virtual size_t heapBytes() const override
returns the amount of memory this object occupies on heap
Definition MRObjectTransformWidget.h:100
ChangeCenterAction(const std::string &name, ITransformControls &controls)
Definition MRObjectTransformWidget.h:87
virtual std::string name() const override
Definition MRObjectTransformWidget.h:91
virtual void action(HistoryAction::Type) override
This function is called on history action (undo, redo, etc.)
Definition MRObjectTransformWidget.h:93
Definition MRObjectTransformWidget.h:43
virtual void stopModify_()=0
const Vector3f & getCenter() const
Definition MRObjectTransformWidget.h:48
virtual void updateVisualTransformMode_(ControlBit showMask, ViewportMask viewportMask)=0
void hover()
Definition MRObjectTransformWidget.h:71
virtual void updateRotation(Axis ax, const AffineXf3f &xf, float startAngle, float endAngle)=0
void stopModify()
Definition MRObjectTransformWidget.h:73
MRVIEWER_API void updateVisualTransformMode(ControlBit showMask, ViewportMask viewportMask, const AffineXf3f &xf)
ControlBit getHoveredControl() const
Definition MRObjectTransformWidget.h:63
void setPickThrough(bool on)
Definition MRObjectTransformWidget.h:59
bool getPickThrough() const
Definition MRObjectTransformWidget.h:60
virtual void update()=0
virtual void updateTranslation(Axis ax, const Vector3f &startMove, const Vector3f &endMove)=0
void setTransformModesValidator(TransformModesValidator validator)
Definition MRObjectTransformWidget.h:56
virtual ControlBit hover_(bool pickThrough)=0
virtual void init(std::shared_ptr< Object > parent)=0
MRVIEWER_API void setCenter(const Vector3f &center)
virtual ~ITransformControls()=default
virtual float getRadius() const
Definition MRObjectTransformWidget.h:52
Definition MRObjectTransformWidget.h:262
virtual std::string name() const override
Definition MRObjectTransformWidget.h:275
virtual size_t heapBytes() const override
returns the amount of memory this object occupies on heap
Definition MRObjectTransformWidget.h:291
ChangeXfAction(const std::string &name, ObjectTransformWidget &widget)
Definition MRObjectTransformWidget.h:264
virtual void action(HistoryAction::Type) override
This function is called on history action (undo, redo, etc.)
Definition MRObjectTransformWidget.h:280
Definition MRObjectTransformWidget.h:194
MRVIEWER_API AffineXf3f getControlsXf(ViewportId id={}) const
void setStartModifyCallback(std::function< void()> callback)
Definition MRObjectTransformWidget.h:253
void setAddXfCallback(std::function< void(const AffineXf3f &)> callback)
Definition MRObjectTransformWidget.h:255
void setRotateTooltipCallback(std::function< void(float)> callback)
Definition MRObjectTransformWidget.h:248
AxisTransformMode getAxisTransformMode() const
Definition MRObjectTransformWidget.h:221
void setStopModifyCallback(std::function< void()> callback)
Definition MRObjectTransformWidget.h:251
std::shared_ptr< Object > getRootObject() const
Definition MRObjectTransformWidget.h:226
ControlBit getTransformModeMask(ViewportId id={}) const
Definition MRObjectTransformWidget.h:206
MRVIEWER_API void setControlsXf(const AffineXf3f &xf, ViewportId id={})
MRVIEWER_API void reset()
void setTranslateTooltipCallback(std::function< void(float)> callback)
Definition MRObjectTransformWidget.h:246
MRVIEWER_API void followObjVisibility(const std::weak_ptr< Object > &obj)
AxisTransformMode
Definition MRObjectTransformWidget.h:212
@ AxisScaling
Definition MRObjectTransformWidget.h:216
@ AxisTranslation
Definition MRObjectTransformWidget.h:214
@ UniformScaling
Definition MRObjectTransformWidget.h:218
std::shared_ptr< T > getControlsAs() const
Definition MRObjectTransformWidget.h:231
std::shared_ptr< ITransformControls > getControls() const
Definition MRObjectTransformWidget.h:229
void setAxisTransformMode(AxisTransformMode mode)
Definition MRObjectTransformWidget.h:223
void setApproveXfCallback(std::function< bool(const AffineXf3f &)> callback)
Definition MRObjectTransformWidget.h:258
void setScaleTooltipCallback(std::function< void(float)> callback)
Definition MRObjectTransformWidget.h:244
MRVIEWER_API void create(const Box3f &box, const AffineXf3f &xf, std::shared_ptr< ITransformControls > controls={})
MRVIEWER_API void setTransformMode(ControlBit mask, ViewportId id={})
Definition MRObjectTransformWidget.h:128
virtual MRVIEWER_API void init(std::shared_ptr< Object > parent) override
MRVIEWER_API void setVisualParams(const VisualParams &params)
virtual float getRadius() const override
Definition MRObjectTransformWidget.h:158
virtual MRVIEWER_API ~TransformControls()
static MRVIEWER_API TransformModesValidator ThresholdDotValidator(float thresholdDot)
const VisualParams & getVisualParams() const
Definition MRObjectTransformWidget.h:151
virtual MRVIEWER_API void update() override
virtual MRVIEWER_API void updateRotation(Axis ax, const AffineXf3f &xf, float startAngle, float endAngle) override
MRVIEWER_API void setWidth(float width)
virtual MRVIEWER_API void updateTranslation(Axis ax, const Vector3f &startMove, const Vector3f &endMove) override
float getWidth() const
Definition MRObjectTransformWidget.h:161
Definition MRViewportId.h:16
stores mask of viewport unique identifiers
Definition MRViewportId.h:38
Definition MRViewportProperty.h:17
represents a 3-dimentional float-typed vector
Definition MRDotNet/MRVector3.h:8
auto width(const Box< V > &box)
returns size along x axis
Definition MRMesh/MRBox.h:230
@ None
special value not to limit path in one slice
Definition MRVoxelPath.h:33
Definition MRCameraOrientationPlugin.h:7
Axis
Definition MRAxis.h:6
MouseButton
Definition MRMouse.h:9
std::function< ControlBit(const Vector3f &center, const AffineXf3f &xf, ViewportId)> TransformModesValidator
Definition MRObjectTransformWidget.h:38
ControlBit
Definition MRObjectTransformWidget.h:22
Contour3< float > Contour3f
Definition MRMesh/MRMeshFwd.h:276
Definition MRColor.h:9
Definition MRViewerEventsListener.h:29
Definition MRObjectTransformWidget.h:131
MRVIEWER_API void update(const Box3f &box)