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