OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::GLGizmoAlignment Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/Gizmos/GLGizmoAlignment.hpp>

Collaboration diagram for Slic3r::GUI::GLGizmoAlignment:

Classes

struct  ObjectInfo

Public Types

enum class  AlignType {
  NONE = -1 , CENTER_X , CENTER_Y , CENTER_Z ,
  Y_MAX , Y_MIN , X_MAX , X_MIN ,
  Z_MAX , Z_MIN , DISTRIBUTE_X , DISTRIBUTE_Y ,
  DISTRIBUTE_Z
}

Public Member Functions

 GLGizmoAlignment (GLCanvas3D &canvas)
 ~GLGizmoAlignment ()=default
bool align_objects (AlignType type, bool align_parent=false)
bool distribute_objects (AlignType type)
bool align_to_center (AlignType type, bool align_parent=false)
bool align_to_y_max (bool align_parent=false)
bool align_to_y_min (bool align_parent=false)
bool align_to_x_max (bool align_parent=false)
bool align_to_x_min (bool align_parent=false)
bool align_to_z_max (bool align_parent=false)
bool align_to_z_min (bool align_parent=false)
bool distribute_x ()
bool distribute_y ()
bool distribute_z ()
bool can_align (AlignType type, bool align_parent=false) const
bool can_distribute (AlignType type) const
void set_object_cs (bool flag)
Matrix3d reference_basis (bool align_parent) const
std::vector< ObjectInfo > get_selected_objects_info (BoundingBoxf3 &big_bb, const Matrix3d &basis) const
double get_current_coord (std::string operation_name, BoundingBoxf3 &bbox)
Vec3d generate_displacement (std::string operation_name, double offset)
bool is_parts_selection (bool align_parent) const
std::vector< const GLVolume * > get_selected_part_volumes () const
BoundingBoxf3 get_items_box (const Matrix3d &basis) const
BoundingBoxf3 get_parent_box (const Matrix3d &basis) const
size_t get_items_count (AlignType type, bool align_parent, std::string *why_not=nullptr) const

Private Member Functions

template<typename GetCoordFunc, typename SetCoordFunc>
bool align_objects_generic (GetCoordFunc get_coord, SetCoordFunc set_coord, const std::string &operation_name, bool align_parent=false)
template<typename GetCoordFunc>
bool distribute_objects_generic (GetCoordFunc get_coord, int axis, const std::string &operation_name)
Selection & get_selection () const
bool take_snapshot (const std::string &name)
void apply_transformation (int obj_idx, int inst_idx, const Vec3d &displacement)
void finish_operation (bool force_volume_move=false)

Private Attributes

GLCanvas3D & m_canvas
bool m_object_cs {false}

Detailed Description

Member Enumeration Documentation

◆ AlignType

Enumerator
NONE 
CENTER_X 
CENTER_Y 
CENTER_Z 
Y_MAX 
Y_MIN 
X_MAX 
X_MIN 
Z_MAX 
Z_MIN 
DISTRIBUTE_X 
DISTRIBUTE_Y 
DISTRIBUTE_Z 
19 {
20 NONE = -1,
21 CENTER_X,
22 CENTER_Y,
23 CENTER_Z,
24 Y_MAX,
25 Y_MIN,
26 X_MAX,
27 X_MIN,
28 Z_MAX,
29 Z_MIN,
30 DISTRIBUTE_X,
31 DISTRIBUTE_Y,
32 DISTRIBUTE_Z
33 };
@ NONE
Definition SideTools.hpp:27

Constructor & Destructor Documentation

◆ GLGizmoAlignment()

Slic3r::GUI::GLGizmoAlignment::GLGizmoAlignment ( GLCanvas3D & canvas)
explicit
53 : m_canvas(canvas)
54{
55}
GLCanvas3D & m_canvas
Definition GLGizmoAlignment.hpp:90

References m_canvas.

◆ ~GLGizmoAlignment()

Slic3r::GUI::GLGizmoAlignment::~GLGizmoAlignment ( )
default

Member Function Documentation

◆ align_objects()

bool Slic3r::GUI::GLGizmoAlignment::align_objects ( AlignType type,
bool align_parent = false )
58{
59 if (!can_align(type, align_parent)) {
60 return false;
61 }
62
63 switch (type) {
64 case AlignType::CENTER_X: return align_to_center(type, align_parent);
65 case AlignType::CENTER_Y: return align_to_center(type, align_parent);
66 case AlignType::CENTER_Z: return align_to_center(type, align_parent);
67 case AlignType::Y_MAX: return align_to_y_max(align_parent);
68 case AlignType::Y_MIN: return align_to_y_min(align_parent);
69 case AlignType::X_MAX: return align_to_x_max(align_parent);
70 case AlignType::X_MIN: return align_to_x_min(align_parent);
71 case AlignType::Z_MAX: return align_to_z_max(align_parent);
72 case AlignType::Z_MIN: return align_to_z_min(align_parent);
73 default:
74 return false;
75 }
76}
bool align_to_z_min(bool align_parent=false)
Definition GLGizmoAlignment.cpp:239
bool can_align(AlignType type, bool align_parent=false) const
Definition GLGizmoAlignment.cpp:533
bool align_to_x_min(bool align_parent=false)
Definition GLGizmoAlignment.cpp:126
bool align_to_x_max(bool align_parent=false)
Definition GLGizmoAlignment.cpp:116
bool align_to_z_max(bool align_parent=false)
Definition GLGizmoAlignment.cpp:229
bool align_to_y_min(bool align_parent=false)
Definition GLGizmoAlignment.cpp:106
bool align_to_y_max(bool align_parent=false)
Definition GLGizmoAlignment.cpp:96
@ Y_MIN
Definition GLGizmoAlignment.hpp:25
@ Z_MIN
Definition GLGizmoAlignment.hpp:29
@ CENTER_X
Definition GLGizmoAlignment.hpp:21
@ X_MAX
Definition GLGizmoAlignment.hpp:26
@ X_MIN
Definition GLGizmoAlignment.hpp:27
@ CENTER_Y
Definition GLGizmoAlignment.hpp:22
@ Y_MAX
Definition GLGizmoAlignment.hpp:24
@ Z_MAX
Definition GLGizmoAlignment.hpp:28
@ CENTER_Z
Definition GLGizmoAlignment.hpp:23
bool align_to_center(AlignType type, bool align_parent=false)
Definition GLGizmoAlignment.cpp:136

References align_to_center(), align_to_x_max(), align_to_x_min(), align_to_y_max(), align_to_y_min(), align_to_z_max(), align_to_z_min(), can_align(), CENTER_X, CENTER_Y, CENTER_Z, X_MAX, X_MIN, Y_MAX, Y_MIN, Z_MAX, and Z_MIN.

Referenced by Slic3r::GUI::MenuFactory::append_menu_item_align_distribute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ align_objects_generic()

template<typename GetCoordFunc, typename SetCoordFunc>
bool Slic3r::GUI::GLGizmoAlignment::align_objects_generic ( GetCoordFunc get_coord,
SetCoordFunc set_coord,
const std::string & operation_name,
bool align_parent = false )
private
278{
279 const Matrix3d basis = reference_basis(align_parent);
280 if (align_parent) {
281 // Find reference coordinate
282 BoundingBoxf3 parent_box = get_parent_box(basis);
283 double reference_coord = get_current_coord(operation_name, parent_box);
284 // Handle parts selection differently
285 if (is_parts_selection(true)) {
286 if (!take_snapshot("align to parent node " + operation_name)) {
287 return false;
288 }
289
291
292 const std::vector<const GLVolume *> volumes = get_selected_part_volumes();
293 if (volumes.empty())
294 return false;
295 BoundingBoxf3 selection_bbox = get_items_box(basis);
296 double current_coord = get_current_coord(operation_name, selection_bbox);
297 Vec3d displacement = generate_displacement(operation_name, reference_coord - current_coord);
298 for (const GLVolume *volume : volumes) {
299 if (displacement.norm() > 1e-6) {
300 get_selection().translate(volume->object_idx(), volume->instance_idx(), volume->volume_idx(), basis * displacement, false);
301 }
302 }
303
304 finish_operation(true);
305 return true;
306 }
307
308 // Handle objects selection (original logic)
309 BoundingBoxf3 big_bb;
310 auto objects = get_selected_objects_info(big_bb, basis);
311 if (objects.empty()) return false;
312
313 if (!take_snapshot("align to parent node " + operation_name)) { return false; }
314
316
317 double current_coord = get_current_coord(operation_name, big_bb);
318 Vec3d displacement = generate_displacement(operation_name, reference_coord - current_coord);
319
320 for (const auto &obj : objects) {
321 if (displacement.norm() > 1e-6) {
322 apply_transformation(obj.object_idx, obj.instance_idx, basis * displacement);
323 }
324 }
325
327 return true;
328 }
329 // Handle parts selection differently
330 if (is_parts_selection(false)) {
331 if (!take_snapshot(operation_name)) {
332 return false;
333 }
334
336
337 const std::vector<const GLVolume*> volumes = get_selected_part_volumes();
338 if (volumes.empty()) return false;
339
340 // Find reference coordinate
341 double reference_coord = 0.0;
342 bool first = true;
343
344 for (const GLVolume* volume : volumes) {
345 BoundingBoxf3 bbox = volume_box_in_frame(*volume, basis);
346 double coord = 0.0;
347
348 if (operation_name.find("X Max") != std::string::npos) {
349 coord = bbox.max.x();
350 } else if (operation_name.find("X Min") != std::string::npos) {
351 coord = bbox.min.x();
352 } else if (operation_name.find("Y Max") != std::string::npos) {
353 coord = bbox.max.y();
354 } else if (operation_name.find("Y Min") != std::string::npos) {
355 coord = bbox.min.y();
356 } else if (operation_name.find("Z Max") != std::string::npos) {
357 coord = bbox.max.z();
358 } else if (operation_name.find("Z Min") != std::string::npos) {
359 coord = bbox.min.z();
360 }
361
362 if (first) {
363 reference_coord = coord;
364 first = false;
365 } else {
366 if (operation_name.find("Max") != std::string::npos) {
367 reference_coord = std::max(reference_coord, coord);
368 } else if (operation_name.find("Min") != std::string::npos) {
369 reference_coord = std::min(reference_coord, coord);
370 }
371 }
372 }
373
374 for (const GLVolume* volume : volumes) {
375 BoundingBoxf3 bbox = volume_box_in_frame(*volume, basis);
376 double current_coord = 0.0;
377
378 if (operation_name.find("X Max") != std::string::npos) {
379 current_coord = bbox.max.x();
380 } else if (operation_name.find("X Min") != std::string::npos) {
381 current_coord = bbox.min.x();
382 } else if (operation_name.find("Y Max") != std::string::npos) {
383 current_coord = bbox.max.y();
384 } else if (operation_name.find("Y Min") != std::string::npos) {
385 current_coord = bbox.min.y();
386 } else if (operation_name.find("Z Max") != std::string::npos) {
387 current_coord = bbox.max.z();
388 } else if (operation_name.find("Z Min") != std::string::npos) {
389 current_coord = bbox.min.z();
390 }
391
392 Vec3d displacement = Vec3d::Zero();
393
394 if (operation_name.find("X") != std::string::npos) {
395 displacement.x() = reference_coord - current_coord;
396 } else if (operation_name.find("Y") != std::string::npos) {
397 displacement.y() = reference_coord - current_coord;
398 } else if (operation_name.find("Z") != std::string::npos) {
399 displacement.z() = reference_coord - current_coord;
400 }
401
402 if (displacement.norm() > 1e-6) {
403 get_selection().translate(volume->object_idx(), volume->instance_idx(), volume->volume_idx(), basis * displacement, false);
404 }
405 }
406
407 finish_operation(true);
408 return true;
409 }
410
411 // Handle objects selection (original logic)
412 BoundingBoxf3 big_bb;
413 auto objects = get_selected_objects_info(big_bb, basis);
414 if (objects.empty()) return false;
415
416 if (!take_snapshot(operation_name)) {
417 return false;
418 }
419
421
422 double reference_coord = get_coord(objects[0]);
423 for (const auto& obj : objects) {
424 double coord = get_coord(obj);
425 if (operation_name.find("Max") != std::string::npos) {
426 reference_coord = std::max(reference_coord, coord);
427 } else if (operation_name.find("Min") != std::string::npos) {
428 reference_coord = std::min(reference_coord, coord);
429 }
430 }
431
432 for (const auto& obj : objects) {
433 double current_coord = get_coord(obj);
434 Vec3d displacement = Vec3d::Zero();
435 set_coord(displacement, reference_coord, current_coord);
436
437 if (displacement.norm() > 1e-6) {
438 apply_transformation(obj.object_idx, obj.instance_idx, basis * displacement);
439 }
440 }
441
443 return true;
444}
void finish_operation(bool force_volume_move=false)
Definition GLGizmoAlignment.cpp:709
BoundingBoxf3 get_parent_box(const Matrix3d &basis) const
Definition GLGizmoAlignment.cpp:664
void apply_transformation(int obj_idx, int inst_idx, const Vec3d &displacement)
Definition GLGizmoAlignment.cpp:704
Selection & get_selection() const
Definition GLGizmoAlignment.cpp:693
Vec3d generate_displacement(std::string operation_name, double offset)
Definition GLGizmoAlignment.cpp:569
Matrix3d reference_basis(bool align_parent) const
Definition GLGizmoAlignment.cpp:581
std::vector< ObjectInfo > get_selected_objects_info(BoundingBoxf3 &big_bb, const Matrix3d &basis) const
Definition GLGizmoAlignment.cpp:594
bool is_parts_selection(bool align_parent) const
Definition GLGizmoAlignment.cpp:621
bool take_snapshot(const std::string &name)
Definition GLGizmoAlignment.cpp:698
double get_current_coord(std::string operation_name, BoundingBoxf3 &bbox)
Definition GLGizmoAlignment.cpp:544
std::vector< const GLVolume * > get_selected_part_volumes() const
Definition GLGizmoAlignment.cpp:630
BoundingBoxf3 get_items_box(const Matrix3d &basis) const
Definition GLGizmoAlignment.cpp:653
void translate(const Vec3d &displacement, TransformationType transformation_type)
Definition Selection.cpp:1279
void setup_cache()
Definition Selection.cpp:1238
BoundingBoxf3 volume_box_in_frame(const GLVolume &volume, const Matrix3d &basis)
Definition GLGizmoAlignment.cpp:46
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
Eigen::Matrix< double, 3, 3, Eigen::DontAlign > Matrix3d
Definition Point.hpp:86

References apply_transformation(), finish_operation(), generate_displacement(), get_current_coord(), get_items_box(), get_parent_box(), get_selected_objects_info(), get_selected_part_volumes(), get_selection(), is_parts_selection(), Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max, Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min, reference_basis(), Slic3r::GUI::Selection::setup_cache(), take_snapshot(), and Slic3r::GUI::Selection::translate().

Referenced by align_to_x_max(), align_to_x_min(), align_to_y_max(), align_to_y_min(), align_to_z_max(), and align_to_z_min().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ align_to_center()

bool Slic3r::GUI::GLGizmoAlignment::align_to_center ( AlignType type,
bool align_parent = false )
137{
138 std::string type_str = type == AlignType::CENTER_X ? "X" : (type == AlignType::CENTER_Y ? "Y" : "Z");
139 std::string operation_name = type == AlignType::CENTER_X ? "X Center" : (type == AlignType::CENTER_Y ? "Y Center" : "Z Center");
140 const Matrix3d basis = reference_basis(align_parent);
141 double selection_center = 0.f;
142 if (align_parent) {
143 BoundingBoxf3 parent_box = get_parent_box(basis);
144 selection_center = get_current_coord(operation_name, parent_box);
145
146 // Handle multiple volume selection
147 if (is_parts_selection(true)) {
148 if (!take_snapshot("Align to parent center " + type_str)) {
149 return false;
150 }
151
153
154 BoundingBoxf3 selection_bbox = get_items_box(basis);
155 double current_coord = get_current_coord(operation_name, selection_bbox);
156 Vec3d displacement = generate_displacement(operation_name, selection_center - current_coord);
157 // Move the selected volumes together so that their collective bounding box is centered in the parent
158 for (const GLVolume *volume : get_selected_part_volumes()) {
159 get_selection().translate(volume->object_idx(), volume->instance_idx(), volume->volume_idx(), basis * displacement, false);
160 }
161 finish_operation(true);
162 return true;
163 }
164 BoundingBoxf3 big_bb;
165 auto objects = get_selected_objects_info(big_bb, basis);
166 if (objects.empty()) return false;
167 // Handle multiple objects or parts selection
168
169 if (!take_snapshot("Align to parent center " + type_str)) {
170 return false;
171 }
172
174 double current_coord = get_current_coord(operation_name, big_bb);
175 Vec3d displacement = generate_displacement(operation_name, selection_center - current_coord);
176 // Multiple objects: use selection bounding box for alignment
177 for (const auto &obj : objects) {
178 apply_transformation(obj.object_idx, obj.instance_idx, basis * displacement);
179 }
180
182 return true;
183 }
184 // Handle the parts of a single instance
185 if (is_parts_selection(false)) {
186 if (!take_snapshot("Align Parts Center " + type_str)){
187 return false;
188 }
189
191
192 BoundingBoxf3 selection_bbox = get_items_box(basis);
193 selection_center = get_current_coord(operation_name, selection_bbox);
194
195 // Move each part to align to the center of their collective bounding box
196 for (const GLVolume *volume : get_selected_part_volumes()) {
197 auto temp_box = volume_box_in_frame(*volume, basis);
198 double current = get_current_coord(operation_name, temp_box);
199 double offset = selection_center - current;
200 Vec3d displacement = generate_displacement(operation_name, offset);
201 get_selection().translate(volume->object_idx(), volume->instance_idx(), volume->volume_idx(), basis * displacement, false);
202 }
203
204 finish_operation(true);
205 return true;
206 }
207 BoundingBoxf3 big_bb;
208 auto objects = get_selected_objects_info(big_bb, basis);
209 if (objects.empty()) return false;
210 // Handle multiple instances
211 selection_center = get_current_coord(operation_name, big_bb);
212
213 if (!take_snapshot("Align Objects Center" + type_str)) {
214 return false;
215 }
216
218 // Multiple objects: use selection bounding box for alignment
219 for (const auto& obj : objects) {
220 BoundingBoxf3 temp_bbox = obj.bbox;
221 double current_coord = get_current_coord(operation_name, temp_bbox);
222 Vec3d displacement = generate_displacement(operation_name, selection_center - current_coord);
223 apply_transformation(obj.object_idx, obj.instance_idx, basis * displacement);
224 }
226 return true;
227}
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582

References apply_transformation(), CENTER_X, CENTER_Y, finish_operation(), generate_displacement(), get_current_coord(), get_items_box(), get_parent_box(), get_selected_objects_info(), get_selected_part_volumes(), get_selection(), is_parts_selection(), Slic3r::offset(), reference_basis(), Slic3r::GUI::Selection::setup_cache(), take_snapshot(), and Slic3r::GUI::Selection::translate().

Referenced by align_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ align_to_x_max()

bool Slic3r::GUI::GLGizmoAlignment::align_to_x_max ( bool align_parent = false)
117{
119 [](const ObjectInfo& obj) { return obj.bbox.max.x(); },
120 [](Vec3d& displacement, double target, double current_max) {
121 displacement.x() = target - current_max;
122 }, "Align X Max", align_parent
123 );
124}
bool align_objects_generic(GetCoordFunc get_coord, SetCoordFunc set_coord, const std::string &operation_name, bool align_parent=false)
Definition GLGizmoAlignment.cpp:277
Definition GLGizmoAlignment.hpp:34

References align_objects_generic(), Slic3r::GUI::GLGizmoAlignment::ObjectInfo::bbox, and Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max.

Referenced by align_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ align_to_x_min()

bool Slic3r::GUI::GLGizmoAlignment::align_to_x_min ( bool align_parent = false)
127{
129 [](const ObjectInfo& obj) { return obj.bbox.min.x(); },
130 [](Vec3d& displacement, double target, double current_min) {
131 displacement.x() = target - current_min;
132 }, "Align X Min", align_parent
133 );
134}

References align_objects_generic(), Slic3r::GUI::GLGizmoAlignment::ObjectInfo::bbox, and Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min.

Referenced by align_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ align_to_y_max()

bool Slic3r::GUI::GLGizmoAlignment::align_to_y_max ( bool align_parent = false)
97{
99 [](const ObjectInfo& obj) { return obj.bbox.max.y(); },
100 [](Vec3d& displacement, double target, double current_max) {
101 displacement.y() = target - current_max;
102 }, "Align Y Max", align_parent
103 );
104}

References align_objects_generic(), Slic3r::GUI::GLGizmoAlignment::ObjectInfo::bbox, and Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max.

Referenced by align_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ align_to_y_min()

bool Slic3r::GUI::GLGizmoAlignment::align_to_y_min ( bool align_parent = false)
107{
109 [](const ObjectInfo& obj) { return obj.bbox.min.y(); },
110 [](Vec3d& displacement, double target, double current_min) {
111 displacement.y() = target - current_min;
112 }, "Align Y Min", align_parent
113 );
114}

References align_objects_generic(), Slic3r::GUI::GLGizmoAlignment::ObjectInfo::bbox, and Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min.

Referenced by align_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ align_to_z_max()

bool Slic3r::GUI::GLGizmoAlignment::align_to_z_max ( bool align_parent = false)
230{
232 [](const ObjectInfo& obj) { return obj.bbox.max.z(); },
233 [](Vec3d& displacement, double target, double current_max) {
234 displacement.z() = target - current_max;
235 }, "Align Z Max", align_parent
236 );
237}

References align_objects_generic(), Slic3r::GUI::GLGizmoAlignment::ObjectInfo::bbox, and Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max.

Referenced by align_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ align_to_z_min()

bool Slic3r::GUI::GLGizmoAlignment::align_to_z_min ( bool align_parent = false)
240{
242 [](const ObjectInfo& obj) { return obj.bbox.min.z(); },
243 [](Vec3d& displacement, double target, double current_min) {
244 displacement.z() = target - current_min;
245 }, "Align Z Min", align_parent
246 );
247}

References align_objects_generic(), Slic3r::GUI::GLGizmoAlignment::ObjectInfo::bbox, and Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min.

Referenced by align_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_transformation()

void Slic3r::GUI::GLGizmoAlignment::apply_transformation ( int obj_idx,
int inst_idx,
const Vec3d & displacement )
private
705{
706 get_selection().translate(obj_idx, inst_idx, displacement);
707}

References get_selection(), and Slic3r::GUI::Selection::translate().

Referenced by align_objects_generic(), align_to_center(), and distribute_objects_generic().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ can_align()

bool Slic3r::GUI::GLGizmoAlignment::can_align ( AlignType type,
bool align_parent = false ) const
534{
535 return get_items_count(type, align_parent) >= (align_parent ? 1 : 2);
536}
size_t get_items_count(AlignType type, bool align_parent, std::string *why_not=nullptr) const
Definition GLGizmoAlignment.cpp:719

References get_items_count().

Referenced by align_objects(), and Slic3r::GUI::MenuFactory::append_menu_item_align_distribute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ can_distribute()

bool Slic3r::GUI::GLGizmoAlignment::can_distribute ( AlignType type) const
539{
540 return (type == AlignType::DISTRIBUTE_X || type == AlignType::DISTRIBUTE_Y || type == AlignType::DISTRIBUTE_Z) &&
541 get_items_count(type, false) >= 3;
542}
@ DISTRIBUTE_Z
Definition GLGizmoAlignment.hpp:32
@ DISTRIBUTE_X
Definition GLGizmoAlignment.hpp:30
@ DISTRIBUTE_Y
Definition GLGizmoAlignment.hpp:31

References DISTRIBUTE_X, DISTRIBUTE_Y, DISTRIBUTE_Z, and get_items_count().

Referenced by Slic3r::GUI::MenuFactory::append_menu_item_align_distribute(), and distribute_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ distribute_objects()

bool Slic3r::GUI::GLGizmoAlignment::distribute_objects ( AlignType type)
79{
80 if (!can_distribute(type)) {
81 return false;
82 }
83
84 switch (type) {
86 return distribute_x();
88 return distribute_y();
90 return distribute_z();
91 default:
92 return false;
93 }
94}
bool distribute_z()
Definition GLGizmoAlignment.cpp:267
bool distribute_x()
Definition GLGizmoAlignment.cpp:258
bool distribute_y()
Definition GLGizmoAlignment.cpp:249
bool can_distribute(AlignType type) const
Definition GLGizmoAlignment.cpp:538

References can_distribute(), DISTRIBUTE_X, distribute_x(), DISTRIBUTE_Y, distribute_y(), DISTRIBUTE_Z, and distribute_z().

Referenced by Slic3r::GUI::MenuFactory::append_menu_item_align_distribute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ distribute_objects_generic()

template<typename GetCoordFunc>
bool Slic3r::GUI::GLGizmoAlignment::distribute_objects_generic ( GetCoordFunc get_coord,
int axis,
const std::string & operation_name )
private
448{
449 const Matrix3d basis = reference_basis(false);
450 if (is_parts_selection(false)) {
451 const std::vector<const GLVolume*> volumes = get_selected_part_volumes();
452 if (volumes.size() < 3) return false;
453 if (!take_snapshot(operation_name)) {
454 return false;
455 }
457
458 struct VolEntry { const GLVolume* v; double coord; };
459 std::vector<VolEntry> entries;
460 entries.reserve(volumes.size());
461 for (const GLVolume* v : volumes) {
462 BoundingBoxf3 bbox = volume_box_in_frame(*v, basis);
463 Vec3d c = bbox.center();
464 double coord = (axis == 0 ? c.x() : axis == 1 ? c.y() : c.z());
465 entries.push_back({v, coord});
466 }
467
468 std::sort(entries.begin(), entries.end(), [](const VolEntry& a, const VolEntry& b){ return a.coord < b.coord; });
469
470 BoundingBoxf3 selection_bbox = get_items_box(basis);
471 BoundingBoxf3 left_bbox = volume_box_in_frame(*entries.front().v, basis);
472 BoundingBoxf3 right_bbox = volume_box_in_frame(*entries.back().v, basis);
473 auto axis_extent = [&](const BoundingBoxf3 &bb) { return (axis == 0 ? (bb.max.x() - bb.min.x()) : axis == 1 ? (bb.max.y() - bb.min.y()) : (bb.max.z() - bb.min.z())); };
474 double left_width = axis_extent(left_bbox);
475 double right_width = axis_extent(right_bbox);
476 double bbox_min = (axis == 0 ? selection_bbox.min.x() : axis == 1 ? selection_bbox.min.y() : selection_bbox.min.z());
477 double bbox_max = (axis == 0 ? selection_bbox.max.x() : axis == 1 ? selection_bbox.max.y() : selection_bbox.max.z());
478 double min_center = bbox_min + left_width * 0.5;
479 double max_center = bbox_max - right_width * 0.5;
480 double total_distance = max_center - min_center;
481 double interval = (entries.size() > 1) ? total_distance / (entries.size() - 1) : 0;
482 for (size_t i = 1; i < entries.size() - 1; ++i) {
483 double target_coord = min_center + i * interval;
484 double current_coord = entries[i].coord;
485 double offset = target_coord - current_coord;
486
487 if (std::abs(offset) > 1e-6) {
488 Vec3d displacement = Vec3d::Zero();
489 displacement[axis] = offset;
490 const GLVolume *v = entries[i].v;
491 get_selection().translate(v->object_idx(), v->instance_idx(), v->volume_idx(), basis * displacement, false);
492 }
493 }
494
495 finish_operation(true);
496 return true;
497 }
498 BoundingBoxf3 big_bb;
499 auto objects = get_selected_objects_info(big_bb, basis);
500 if (objects.size() < 3) return false;
501
502 if (!take_snapshot(operation_name)) {
503 return false;
504 }
505
507
508 std::sort(objects.begin(), objects.end(),
509 [&get_coord](const ObjectInfo& a, const ObjectInfo& b) {
510 return get_coord(a) < get_coord(b);
511 });
512
513 double min_coord = get_coord(objects.front());
514 double max_coord = get_coord(objects.back());
515 double total_distance = max_coord - min_coord;
516 double interval = (objects.size() > 1) ? total_distance / (objects.size() - 1) : 0;
517 for (size_t i = 1; i < objects.size() - 1; ++i) {
518 double target_coord = min_coord + i * interval;
519 double current_coord = get_coord(objects[i]);
520 double offset = target_coord - current_coord;
521
522 if (std::abs(offset) > 1e-6) {
523 Vec3d displacement = Vec3d::Zero();
524 displacement[axis] = offset;
525 apply_transformation(objects[i].object_idx, objects[i].instance_idx, basis * displacement);
526 }
527 }
528
530 return true;
531}

References apply_transformation(), Slic3r::BoundingBox3Base< PointType >::center(), finish_operation(), get_items_box(), get_selected_objects_info(), get_selected_part_volumes(), get_selection(), Slic3r::GLVolume::instance_idx(), is_parts_selection(), Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max, Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min, Slic3r::GLVolume::object_idx(), Slic3r::offset(), reference_basis(), Slic3r::GUI::Selection::setup_cache(), take_snapshot(), Slic3r::GUI::Selection::translate(), and Slic3r::GLVolume::volume_idx().

Referenced by distribute_x(), distribute_y(), and distribute_z().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ distribute_x()

bool Slic3r::GUI::GLGizmoAlignment::distribute_x ( )
259{
261 [](const ObjectInfo& obj) { return obj.center.x(); },
262 0,
263 "Distribute X"
264 );
265}
bool distribute_objects_generic(GetCoordFunc get_coord, int axis, const std::string &operation_name)
Definition GLGizmoAlignment.cpp:447

References Slic3r::GUI::GLGizmoAlignment::ObjectInfo::center, and distribute_objects_generic().

Referenced by distribute_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ distribute_y()

bool Slic3r::GUI::GLGizmoAlignment::distribute_y ( )
250{
252 [](const ObjectInfo& obj) { return obj.center.y(); },
253 1,
254 "Distribute Y"
255 );
256}

References Slic3r::GUI::GLGizmoAlignment::ObjectInfo::center, and distribute_objects_generic().

Referenced by distribute_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ distribute_z()

bool Slic3r::GUI::GLGizmoAlignment::distribute_z ( )
268{
270 [](const ObjectInfo& obj) { return obj.center.z(); },
271 2,
272 "Distribute Z"
273 );
274}

References Slic3r::GUI::GLGizmoAlignment::ObjectInfo::center, and distribute_objects_generic().

Referenced by distribute_objects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ finish_operation()

void Slic3r::GUI::GLGizmoAlignment::finish_operation ( bool force_volume_move = false)
private
710{
711 // A part move changes the ModelVolume shared by every copy of the object, so the other copies' volumes must show
712 // it too, or do_move() would write their stale transformation back to the model.
713 if (force_volume_move)
715 // The operation already took its snapshot.
716 m_canvas.do_move("", force_volume_move);
717}
void synchronize_unselected_volumes()
Definition Selection.cpp:3101

References get_selection(), m_canvas, and Slic3r::GUI::Selection::synchronize_unselected_volumes().

Referenced by align_objects_generic(), align_to_center(), and distribute_objects_generic().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_displacement()

Vec3d Slic3r::GUI::GLGizmoAlignment::generate_displacement ( std::string operation_name,
double offset )
569 {
570 Vec3d displacement = Vec3d::Zero();
571 if (operation_name.find("X") != std::string::npos) {
572 displacement.x() = offset;
573 } else if (operation_name.find("Y") != std::string::npos) {
574 displacement.y() = offset;
575 } else if (operation_name.find("Z") != std::string::npos) {
576 displacement.z() = offset;
577 }
578 return displacement;
579}

References Slic3r::offset().

Referenced by align_objects_generic(), and align_to_center().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_current_coord()

double Slic3r::GUI::GLGizmoAlignment::get_current_coord ( std::string operation_name,
BoundingBoxf3 & bbox )
545{
546 double current_coord = 0.0;
547 if (operation_name.find("X Max") != std::string::npos) {
548 current_coord = bbox.max.x();
549 } else if (operation_name.find("X Min") != std::string::npos) {
550 current_coord = bbox.min.x();
551 } else if (operation_name.find("Y Max") != std::string::npos) {
552 current_coord = bbox.max.y();
553 } else if (operation_name.find("Y Min") != std::string::npos) {
554 current_coord = bbox.min.y();
555 } else if (operation_name.find("Z Max") != std::string::npos) {
556 current_coord = bbox.max.z();
557 } else if (operation_name.find("Z Min") != std::string::npos) {
558 current_coord = bbox.min.z();
559 } else if (operation_name.find("X Center") != std::string::npos) {
560 current_coord = bbox.center().x();
561 } else if (operation_name.find("Y Center") != std::string::npos) {
562 current_coord = bbox.center().y();
563 } else if (operation_name.find("Z Center") != std::string::npos) {
564 current_coord = bbox.center().z();
565 }
566 return current_coord;
567}

References Slic3r::BoundingBox3Base< PointType >::center(), Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max, and Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min.

Referenced by align_objects_generic(), and align_to_center().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_items_box()

BoundingBoxf3 Slic3r::GUI::GLGizmoAlignment::get_items_box ( const Matrix3d & basis) const
654{
655 BoundingBoxf3 box;
656 if (is_parts_selection(false)) {
657 for (const GLVolume *volume : get_selected_part_volumes())
658 box.merge(volume_box_in_frame(*volume, basis));
659 } else
660 get_selected_objects_info(box, basis);
661 return box;
662}

References get_selected_objects_info(), get_selected_part_volumes(), is_parts_selection(), and Slic3r::BoundingBox3Base< PointType >::merge().

Referenced by align_objects_generic(), align_to_center(), distribute_objects_generic(), and Slic3r::GUI::GLGizmoMove3D::render_align_preview().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_items_count()

size_t Slic3r::GUI::GLGizmoAlignment::get_items_count ( AlignType type,
bool align_parent,
std::string * why_not = nullptr ) const
720{
721 auto cannot_move = [why_not](const std::string &reason) {
722 if (why_not != nullptr)
723 *why_not = reason;
724 return size_t(0);
725 };
726
727 if (is_parts_selection(align_parent)) {
728 const size_t count = get_selected_part_volumes().size();
729 return count > 0 ? count : cannot_move(_u8L("Parts of a cut object cannot be moved"));
730 }
731
732 // Instances are moved through their instance offsets, which do_move() commits only from an Instance selection.
733 const Selection &selection = get_selection();
734 if (selection.get_mode() != Selection::Instance)
735 return 0;
736
737 const bool is_z = type == AlignType::Z_MIN || type == AlignType::CENTER_Z || type == AlignType::Z_MAX ||
739 // The plate gives no Z target, and aligning to its bottom would duplicate Drop.
740 if (is_z && align_parent)
741 return cannot_move(_u8L("Aligning to the plate is available in X and Y only"));
742
743 PartPlateList &plate_list = wxGetApp().plater()->get_partplate_list();
744 int plate_idx = -1;
745 size_t count = 0;
746 for (const auto &[obj_idx, inst_idxs] : selection.get_content()) {
747 if (obj_idx >= 1000)
748 continue;
749 // Auto-drop would put a raised object back on the bed and leave a lowered one sunk.
750 if (is_z && selection.get_model()->objects[obj_idx]->auto_drop)
751 return cannot_move(_u8L("Turn off Auto-Drop for the selected objects to move them in Z"));
752 if (align_parent) {
753 // The plate holding the selection is the target, so it must hold all of it.
754 for (int inst_idx : inst_idxs) {
755 const int idx = plate_list.find_instance(obj_idx, inst_idx);
756 if (idx == -1 || (plate_idx != -1 && idx != plate_idx))
757 return cannot_move(_u8L("All selected objects must be on the same plate"));
758 plate_idx = idx;
759 }
760 }
761 count += inst_idxs.size();
762 }
763 return count;
764}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
@ Instance
Definition Selection.hpp:54
@ Selection
Definition Shortcuts.hpp:72
#define _u8L(s)
Definition I18N.hpp:11

References _u8L, CENTER_Z, count, DISTRIBUTE_Z, Slic3r::GUI::PartPlateList::find_instance(), Slic3r::GUI::Selection::get_content(), Slic3r::GUI::Selection::get_mode(), Slic3r::GUI::Selection::get_model(), get_selected_part_volumes(), get_selection(), Slic3r::GUI::Selection::Instance, is_parts_selection(), Slic3r::Model::objects, Z_MAX, and Z_MIN.

Referenced by can_align(), can_distribute(), and Slic3r::GUI::GLGizmoMove3D::render_align_preview().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_parent_box()

BoundingBoxf3 Slic3r::GUI::GLGizmoAlignment::get_parent_box ( const Matrix3d & basis) const
665{
666 const Selection &selection = get_selection();
667 if (is_parts_selection(true)) {
668 const ModelObject *object = selection.get_model()->objects[selection.get_object_idx()];
669 return instance_box_in_frame(*object, *object->instances[selection.get_instance_idx()], world_to_frame(basis), true);
670 }
671
672 // can_align() requires every selected instance on one plate, so the first one gives the plate.
673 BoundingBoxf3 box;
674 PartPlateList &plate_list = wxGetApp().plater()->get_partplate_list();
675 for (const auto &[obj_idx, inst_idxs] : selection.get_content()) {
676 if (obj_idx >= 1000 || inst_idxs.empty())
677 continue;
678 PartPlate *plate = plate_list.get_plate(plate_list.find_instance(obj_idx, *inst_idxs.begin()));
679 if (plate == nullptr)
680 break;
681 BoundingBoxf3 instances_box;
682 get_selected_objects_info(instances_box, Matrix3d::Identity());
683 box = plate->get_plate_box();
684 box.max.z() = instances_box.max.z();
685 // Keep the aligned objects off the plate edge.
686 box.min += Vec3d(0.1, 0.1, 0.1);
687 box.max -= Vec3d(0.1, 0.1, 0.1);
688 break;
689 }
690 return box;
691}
Transform3d world_to_frame(const Matrix3d &basis)
Definition GLGizmoAlignment.cpp:25
BoundingBoxf3 instance_box_in_frame(const ModelObject &object, const ModelInstance &instance, const Transform3d &to_frame, bool convex_hull)
Definition GLGizmoAlignment.cpp:33

References Slic3r::GUI::PartPlateList::find_instance(), Slic3r::GUI::Selection::get_content(), Slic3r::GUI::Selection::get_instance_idx(), Slic3r::GUI::Selection::get_model(), Slic3r::GUI::Selection::get_object_idx(), Slic3r::GUI::PartPlateList::get_plate(), Slic3r::GUI::PartPlate::get_plate_box(), get_selected_objects_info(), get_selection(), Slic3r::ModelObject::instances, is_parts_selection(), Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max, Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min, and Slic3r::Model::objects.

Referenced by align_objects_generic(), align_to_center(), and Slic3r::GUI::GLGizmoMove3D::render_align_preview().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_selected_objects_info()

std::vector< GLGizmoAlignment::ObjectInfo > Slic3r::GUI::GLGizmoAlignment::get_selected_objects_info ( BoundingBoxf3 & big_bb,
const Matrix3d & basis ) const
595{
596 std::vector<ObjectInfo> objects;
597 Selection& selection = get_selection();
598
599 if (selection.is_empty()) return objects;
600
601 const Transform3d to_frame = world_to_frame(basis);
602 const auto& content = selection.get_content();
603 for (const auto& obj_it : content) {
604 for (const auto& inst_idx : obj_it.second) {
605 int obj_idx = obj_it.first;
606
607 if (obj_idx >= 0 && obj_idx < selection.get_model()->objects.size()) {
608 ModelObject* object = selection.get_model()->objects[obj_idx];
609 if (inst_idx >= 0 && inst_idx < object->instances.size()) {
610 BoundingBoxf3 bbox = instance_box_in_frame(*object, *object->instances[inst_idx], to_frame, false);
611 big_bb.merge(bbox);
612 objects.emplace_back(obj_idx, inst_idx, bbox);
613 }
614 }
615 }
616 }
617
618 return objects;
619}
Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign > Transform3d
Definition Point.hpp:96

References Slic3r::GUI::Selection::get_content(), Slic3r::GUI::Selection::get_model(), get_selection(), Slic3r::ModelObject::instances, Slic3r::GUI::Selection::is_empty(), Slic3r::BoundingBox3Base< PointType >::merge(), and Slic3r::Model::objects.

Referenced by align_objects_generic(), align_to_center(), distribute_objects_generic(), get_items_box(), and get_parent_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_selected_part_volumes()

std::vector< const GLVolume * > Slic3r::GUI::GLGizmoAlignment::get_selected_part_volumes ( ) const
631{
632 std::vector<const GLVolume *> volumes;
633 if (!is_parts_selection(false))
634 return volumes;
635
636 const Selection &selection = get_selection();
637 const ModelObject *object = selection.get_model()->objects[selection.get_object_idx()];
638 if (object->is_cut())
639 return volumes;
640
641 for (unsigned int idx : selection.get_volume_idxs()) {
642 const GLVolume *volume = selection.get_volume(idx);
643 if (volume->volume_idx() < 0)
644 continue;
645 // Moving a whole instance's parts leaves its modifiers, negative volumes and support blockers in place,
646 // as dragging a part does.
647 if (selection.get_mode() == Selection::Volume || object->volumes[volume->volume_idx()]->is_model_part())
648 volumes.push_back(volume);
649 }
650 return volumes;
651}
@ Volume
Definition Selection.hpp:53

References Slic3r::GUI::Selection::get_mode(), Slic3r::GUI::Selection::get_model(), Slic3r::GUI::Selection::get_object_idx(), get_selection(), Slic3r::GUI::Selection::get_volume(), Slic3r::GUI::Selection::get_volume_idxs(), Slic3r::ModelObject::is_cut(), is_parts_selection(), Slic3r::Model::objects, Slic3r::GUI::Selection::Volume, Slic3r::GLVolume::volume_idx(), and Slic3r::ModelObject::volumes.

Referenced by align_objects_generic(), align_to_center(), distribute_objects_generic(), get_items_box(), and get_items_count().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_selection()

Selection & Slic3r::GUI::GLGizmoAlignment::get_selection ( ) const
private
694{
695 return m_canvas.get_selection();
696}

References m_canvas.

Referenced by align_objects_generic(), align_to_center(), apply_transformation(), distribute_objects_generic(), finish_operation(), get_items_count(), get_parent_box(), get_selected_objects_info(), get_selected_part_volumes(), is_parts_selection(), and reference_basis().

Here is the caller graph for this function:

◆ is_parts_selection()

bool Slic3r::GUI::GLGizmoAlignment::is_parts_selection ( bool align_parent) const
622{
623 const Selection &selection = get_selection();
624 const auto &content = selection.get_content();
625 if (content.size() != 1 || content.begin()->first >= 1000 || content.begin()->second.size() != 1)
626 return false;
627 return !align_parent || selection.get_mode() == Selection::Volume;
628}

References Slic3r::GUI::Selection::get_content(), Slic3r::GUI::Selection::get_mode(), get_selection(), and Slic3r::GUI::Selection::Volume.

Referenced by align_objects_generic(), align_to_center(), distribute_objects_generic(), get_items_box(), get_items_count(), get_parent_box(), get_selected_part_volumes(), and reference_basis().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reference_basis()

Matrix3d Slic3r::GUI::GLGizmoAlignment::reference_basis ( bool align_parent) const
582{
583 // Plate alignment stays on the world axes.
584 const Selection &selection = get_selection();
585 if (!m_object_cs || selection.is_empty() || (align_parent && !is_parts_selection(true)))
586 return Matrix3d::Identity();
587
588 // The instance of the first selected volume, as the Move gizmo's object coordinate system does.
589 auto transformation = selection.get_first_volume()->get_instance_transformation();
590 transformation.reset_scaling_factor();
591 return transformation.get_matrix_no_offset().linear();
592}
bool m_object_cs
Definition GLGizmoAlignment.hpp:91

References Slic3r::GUI::Selection::get_first_volume(), Slic3r::GLVolume::get_instance_transformation(), get_selection(), Slic3r::GUI::Selection::is_empty(), is_parts_selection(), m_object_cs, and Slic3r::Geometry::Transformation::reset_scaling_factor().

Referenced by align_objects_generic(), align_to_center(), distribute_objects_generic(), and Slic3r::GUI::GLGizmoMove3D::render_align_preview().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_object_cs()

void Slic3r::GUI::GLGizmoAlignment::set_object_cs ( bool flag)
inline
66{ m_object_cs = flag; }

References m_object_cs.

◆ take_snapshot()

bool Slic3r::GUI::GLGizmoAlignment::take_snapshot ( const std::string & name)
private
699{
700 wxGetApp().plater()->take_snapshot(name);
701 return true;
702}

Referenced by align_objects_generic(), align_to_center(), and distribute_objects_generic().

Here is the caller graph for this function:

Member Data Documentation

◆ m_canvas

GLCanvas3D& Slic3r::GUI::GLGizmoAlignment::m_canvas
private

◆ m_object_cs

bool Slic3r::GUI::GLGizmoAlignment::m_object_cs {false}
private
91{false};

Referenced by reference_basis(), and set_object_cs().


The documentation for this class was generated from the following files: