1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
|
#ifndef slic3r_GUI_Selection_hpp_
#define slic3r_GUI_Selection_hpp_
#include <set>
#include "libslic3r/Geometry.hpp"
#include "3DScene.hpp"
#if ENABLE_RENDER_SELECTION_CENTER
class GLUquadric;
typedef class GLUquadric GLUquadricObj;
#endif // ENABLE_RENDER_SELECTION_CENTER
namespace Slic3r {
class Shader;
namespace GUI {
class TransformationType
{
public:
enum Enum {
// Transforming in a world coordinate system
World = 0,
// Transforming in a local coordinate system
Local = 1,
// Absolute transformations, allowed in local coordinate system only.
Absolute = 0,
// Relative transformations, allowed in both local and world coordinate system.
Relative = 2,
// For group selection, the transformation is performed as if the group made a single solid body.
Joint = 0,
// For group selection, the transformation is performed on each object independently.
Independent = 4,
World_Relative_Joint = World | Relative | Joint,
World_Relative_Independent = World | Relative | Independent,
Local_Absolute_Joint = Local | Absolute | Joint,
Local_Absolute_Independent = Local | Absolute | Independent,
Local_Relative_Joint = Local | Relative | Joint,
Local_Relative_Independent = Local | Relative | Independent,
};
TransformationType() : m_value(World) {}
TransformationType(Enum value) : m_value(value) {}
TransformationType& operator=(Enum value) { m_value = value; return *this; }
Enum operator()() const { return m_value; }
bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; }
void set_world() { this->remove(Local); }
void set_local() { this->add(Local); }
void set_absolute() { this->remove(Relative); }
void set_relative() { this->add(Relative); }
void set_joint() { this->remove(Independent); }
void set_independent() { this->add(Independent); }
bool world() const { return !this->has(Local); }
bool local() const { return this->has(Local); }
bool absolute() const { return !this->has(Relative); }
bool relative() const { return this->has(Relative); }
bool joint() const { return !this->has(Independent); }
bool independent() const { return this->has(Independent); }
private:
void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); }
void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); }
Enum m_value;
};
class Selection
{
public:
typedef std::set<unsigned int> IndicesList;
enum EMode : unsigned char
{
Volume,
Instance
};
enum EType : unsigned char
{
Invalid,
Empty,
WipeTower,
SingleModifier,
MultipleModifier,
SingleVolume,
MultipleVolume,
SingleFullObject,
MultipleFullObject,
SingleFullInstance,
MultipleFullInstance,
Mixed
};
private:
struct VolumeCache
{
private:
struct TransformCache
{
Vec3d position;
Vec3d rotation;
Vec3d scaling_factor;
Vec3d mirror;
Transform3d rotation_matrix;
Transform3d scale_matrix;
Transform3d mirror_matrix;
Transform3d full_matrix;
TransformCache();
explicit TransformCache(const Geometry::Transformation& transform);
};
TransformCache m_volume;
TransformCache m_instance;
public:
VolumeCache() {}
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
const Vec3d& get_volume_position() const { return m_volume.position; }
const Vec3d& get_volume_rotation() const { return m_volume.rotation; }
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
const Vec3d& get_volume_mirror() const { return m_volume.mirror; }
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
const Transform3d& get_volume_mirror_matrix() const { return m_volume.mirror_matrix; }
const Transform3d& get_volume_full_matrix() const { return m_volume.full_matrix; }
const Vec3d& get_instance_position() const { return m_instance.position; }
const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
const Vec3d& get_instance_scaling_factor() const { return m_instance.scaling_factor; }
const Vec3d& get_instance_mirror() const { return m_instance.mirror; }
const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; }
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_matrix; }
const Transform3d& get_instance_full_matrix() const { return m_instance.full_matrix; }
};
public:
typedef std::map<unsigned int, VolumeCache> VolumesCache;
typedef std::set<int> InstanceIdxsList;
typedef std::map<int, InstanceIdxsList> ObjectIdxsToInstanceIdxsMap;
class Clipboard
{
Model m_model;
Selection::EMode m_mode;
public:
void reset() { m_model.clear_objects(); }
bool is_empty() const { return m_model.objects.empty(); }
bool is_sla_compliant() const;
ModelObject* add_object() { return m_model.add_object(); }
ModelObject* get_object(unsigned int id) { return (id < (unsigned int)m_model.objects.size()) ? m_model.objects[id] : nullptr; }
const ModelObjectPtrs& get_objects() const { return m_model.objects; }
Selection::EMode get_mode() const { return m_mode; }
void set_mode(Selection::EMode mode) { m_mode = mode; }
};
private:
struct Cache
{
// Cache of GLVolume derived transformation matrices, valid during mouse dragging.
VolumesCache volumes_data;
// Center of the dragged selection, valid during mouse dragging.
Vec3d dragging_center;
// Map from indices of ModelObject instances in Model::objects
// to a set of indices of ModelVolume instances in ModelObject::instances
// Here the index means a position inside the respective std::vector, not ModelID.
ObjectIdxsToInstanceIdxsMap content;
};
// Volumes owned by GLCanvas3D.
GLVolumePtrs* m_volumes;
// Model, not owned.
Model* m_model;
bool m_enabled;
bool m_valid;
EMode m_mode;
EType m_type;
// set of indices to m_volumes
IndicesList m_list;
Cache m_cache;
Clipboard m_clipboard;
mutable BoundingBoxf3 m_bounding_box;
mutable bool m_bounding_box_dirty;
// Bounding box of a selection, with no instance scaling applied. This bounding box
// is useful for absolute scaling of tilted objects in world coordinate space.
mutable BoundingBoxf3 m_unscaled_instance_bounding_box;
mutable bool m_unscaled_instance_bounding_box_dirty;
mutable BoundingBoxf3 m_scaled_instance_bounding_box;
mutable bool m_scaled_instance_bounding_box_dirty;
#if ENABLE_RENDER_SELECTION_CENTER
GLUquadricObj* m_quadric;
#endif // ENABLE_RENDER_SELECTION_CENTER
mutable GLArrow m_arrow;
mutable GLCurvedArrow m_curved_arrow;
mutable float m_scale_factor;
public:
Selection();
#if ENABLE_RENDER_SELECTION_CENTER
~Selection();
#endif // ENABLE_RENDER_SELECTION_CENTER
void set_volumes(GLVolumePtrs* volumes);
bool init();
bool is_enabled() const { return m_enabled; }
void set_enabled(bool enable) { m_enabled = enable; }
Model* get_model() const { return m_model; }
void set_model(Model* model);
EMode get_mode() const { return m_mode; }
void set_mode(EMode mode) { m_mode = mode; }
void add(unsigned int volume_idx, bool as_single_selection = true, bool check_for_already_contained = false);
void remove(unsigned int volume_idx);
void add_object(unsigned int object_idx, bool as_single_selection = true);
void remove_object(unsigned int object_idx);
void add_instance(unsigned int object_idx, unsigned int instance_idx, bool as_single_selection = true);
void remove_instance(unsigned int object_idx, unsigned int instance_idx);
void add_volume(unsigned int object_idx, unsigned int volume_idx, int instance_idx, bool as_single_selection = true);
void remove_volume(unsigned int object_idx, unsigned int volume_idx);
void add_all();
// Update the selection based on the new instance IDs.
void instances_changed(const std::vector<size_t> &instance_ids_selected);
// Update the selection based on the map from old indices to new indices after m_volumes changed.
// If the current selection is by instance, this call may select newly added volumes, if they belong to already selected instances.
void volumes_changed(const std::vector<size_t> &map_volume_old_to_new);
void clear();
bool is_empty() const { return m_type == Empty; }
bool is_wipe_tower() const { return m_type == WipeTower; }
bool is_any_modifier() const { return is_single_modifier() || is_multiple_modifier(); }
bool is_single_modifier() const { return m_type == SingleModifier; }
bool is_multiple_modifier() const { return m_type == MultipleModifier; }
bool is_single_full_instance() const;
bool is_multiple_full_instance() const { return m_type == MultipleFullInstance; }
bool is_single_full_object() const { return m_type == SingleFullObject; }
bool is_multiple_full_object() const { return m_type == MultipleFullObject; }
bool is_single_volume() const { return m_type == SingleVolume; }
bool is_multiple_volume() const { return m_type == MultipleVolume; }
bool is_any_volume() const { return is_single_volume() || is_multiple_volume(); }
bool is_mixed() const { return m_type == Mixed; }
bool is_from_single_instance() const { return get_instance_idx() != -1; }
bool is_from_single_object() const;
bool is_sla_compliant() const;
bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); }
bool requires_uniform_scale() const;
// Returns the the object id if the selection is from a single object, otherwise is -1
int get_object_idx() const;
// Returns the instance id if the selection is from a single object and from a single instance, otherwise is -1
int get_instance_idx() const;
// Returns the indices of selected instances.
// Can only be called if selection is from a single object.
const InstanceIdxsList& get_instance_idxs() const;
const IndicesList& get_volume_idxs() const { return m_list; }
const GLVolume* get_volume(unsigned int volume_idx) const;
const ObjectIdxsToInstanceIdxsMap& get_content() const { return m_cache.content; }
unsigned int volumes_count() const { return (unsigned int)m_list.size(); }
const BoundingBoxf3& get_bounding_box() const;
// Bounding box of a selection, with no instance scaling applied. This bounding box
// is useful for absolute scaling of tilted objects in world coordinate space.
const BoundingBoxf3& get_unscaled_instance_bounding_box() const;
const BoundingBoxf3& get_scaled_instance_bounding_box() const;
void start_dragging();
void translate(const Vec3d& displacement, bool local = false);
void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale, TransformationType transformation_type);
void scale_to_fit_print_volume(const DynamicPrintConfig& config);
void mirror(Axis axis);
void translate(unsigned int object_idx, const Vec3d& displacement);
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
void erase();
void render(float scale_factor = 1.0) const;
#if ENABLE_RENDER_SELECTION_CENTER
void render_center(bool gizmo_is_dragging) const;
#endif // ENABLE_RENDER_SELECTION_CENTER
void render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const;
bool requires_local_axes() const;
void copy_to_clipboard();
void paste_from_clipboard();
const Clipboard& get_clipboard() const { return m_clipboard; }
private:
void update_valid();
void update_type();
void set_caches();
void do_add_volume(unsigned int volume_idx);
void do_add_instance(unsigned int object_idx, unsigned int instance_idx);
void do_add_object(unsigned int object_idx);
void do_remove_volume(unsigned int volume_idx);
void do_remove_instance(unsigned int object_idx, unsigned int instance_idx);
void do_remove_object(unsigned int object_idx);
void calc_bounding_box() const;
void calc_unscaled_instance_bounding_box() const;
void calc_scaled_instance_bounding_box() const;
void set_bounding_boxes_dirty() { m_bounding_box_dirty = true; m_unscaled_instance_bounding_box_dirty = true; m_scaled_instance_bounding_box_dirty = true; }
void render_selected_volumes() const;
void render_synchronized_volumes() const;
void render_bounding_box(const BoundingBoxf3& box, float* color) const;
void render_sidebar_position_hints(const std::string& sidebar_field) const;
void render_sidebar_rotation_hints(const std::string& sidebar_field) const;
void render_sidebar_scale_hints(const std::string& sidebar_field) const;
void render_sidebar_size_hints(const std::string& sidebar_field) const;
void render_sidebar_layers_hints(const std::string& sidebar_field) const;
void render_sidebar_position_hint(Axis axis) const;
void render_sidebar_rotation_hint(Axis axis) const;
void render_sidebar_scale_hint(Axis axis) const;
void render_sidebar_size_hint(Axis axis, double length) const;
public:
enum SyncRotationType {
// Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis.
SYNC_ROTATION_NONE = 0,
// Synchronize fully. Used from "place on bed" feature.
SYNC_ROTATION_FULL = 1,
// Synchronize after rotation by an axis not parallel with Z.
SYNC_ROTATION_GENERAL = 2,
};
void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
void synchronize_unselected_volumes();
private:
void ensure_on_bed();
bool is_from_fully_selected_instance(unsigned int volume_idx) const;
void paste_volumes_from_clipboard();
void paste_objects_from_clipboard();
};
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GUI_Selection_hpp_
|