From afa907504f8f1e044630caf9b008d259601ac9a1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 31 Oct 2018 16:13:07 +0100 Subject: [PATCH 01/12] Fixed autolevel on bed with non uniform scaling --- src/libslic3r/Model.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b68d2a1086..360a215cd5 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -929,16 +929,16 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const double min_z = DBL_MAX; ModelInstance* inst = instances[instance_idx]; - Vec3d local_unit_z = (inst->world_matrix(true).inverse() * Vec3d::UnitZ()).normalized(); + const Transform3d& m = inst->world_matrix(true); for (ModelVolume *v : volumes) { for (uint32_t f = 0; f < v->mesh.stl.stats.number_of_facets; ++f) { const stl_facet* facet = v->mesh.stl.facet_start + f; - min_z = std::min(min_z, local_unit_z.dot(facet->vertex[0].cast())); - min_z = std::min(min_z, local_unit_z.dot(facet->vertex[1].cast())); - min_z = std::min(min_z, local_unit_z.dot(facet->vertex[2].cast())); + min_z = std::min(min_z, Vec3d::UnitZ().dot(m * facet->vertex[0].cast())); + min_z = std::min(min_z, Vec3d::UnitZ().dot(m * facet->vertex[1].cast())); + min_z = std::min(min_z, Vec3d::UnitZ().dot(m * facet->vertex[2].cast())); } } From fd1c5dd2181a03641ae99218b4178fecba2ca95e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 31 Oct 2018 16:22:36 +0100 Subject: [PATCH 02/12] WIP: SL1 profiles, SL1 in wizard, switching between FFF / SLA --- .../printers/PrusaResearch_MK2.5MMU2.png | Bin 0 -> 71328 bytes .../icons/printers/PrusaResearch_SL1.png | Bin 0 -> 41541 bytes resources/profiles/PrusaResearch.idx | 2 + resources/profiles/PrusaResearch.ini | 254 ++++++++++++++++-- slic3r.sublime-project | 2 +- src/libslic3r/Config.hpp | 5 +- src/libslic3r/GCode.cpp | 4 +- src/libslic3r/Print.hpp | 2 +- src/slic3r/Config/Snapshot.cpp | 4 +- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 2 +- src/slic3r/GUI/BedShapeDialog.cpp | 6 +- src/slic3r/GUI/ConfigWizard.hpp | 2 +- src/slic3r/GUI/GUI.cpp | 4 +- src/slic3r/GUI/GUI_App.cpp | 12 +- src/slic3r/GUI/Plater.cpp | 45 ++-- src/slic3r/GUI/Preset.cpp | 66 +++-- src/slic3r/GUI/Preset.hpp | 30 ++- src/slic3r/GUI/PresetBundle.cpp | 59 ++-- src/slic3r/GUI/PresetBundle.hpp | 2 +- src/slic3r/GUI/Tab.cpp | 44 +-- src/slic3r/GUI/Tab.hpp | 11 +- 21 files changed, 408 insertions(+), 148 deletions(-) create mode 100644 resources/icons/printers/PrusaResearch_MK2.5MMU2.png create mode 100644 resources/icons/printers/PrusaResearch_SL1.png diff --git a/resources/icons/printers/PrusaResearch_MK2.5MMU2.png b/resources/icons/printers/PrusaResearch_MK2.5MMU2.png new file mode 100644 index 0000000000000000000000000000000000000000..eb5dccf08c6492825f2706d64805e2ba526d354c GIT binary patch literal 71328 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

X=%+NZBI531A>dAY2^iq9WcOZK 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

JEdk^NC_(}C2HjTtCe_E1U^ zB~cjct|M}3(3)V#aU8s3no_UTX*L^d+PaVgU6CNCsT1k4msQ9XhBc#80F>v!+vo_ii*xu5go=f9ruW8a~?^BeT7UzDs_+P|h&o8F|OT{83*1MT9ZXYA@-luG&HrB@UklQE+calLX-cPtGseX ztzIL|5;ko)6Di=;qjcIOY-5D3MYtMcj-tzzp%g4!TP0}Rhj5D@!<&_r_ML`lET;C912D=I- zD}5D44IN5lbfHg%Q5ZD}Vnq1K+v>g6{F{(BjC}s+e2o$=@2i^TDnclgq`TDSoC~kI z0l2l(UU?-#jAr5(Tg}9g0&6_N$7E?89SKTblE`4V7=g7BUJj)x;P~+)yyTUy$NPwX z`1_A>_St9iu0MM(=bd{V|NR$#mal&O8~o+R{*E|KAK#$8_Y`HoYoB)Q6{Km35Q4NG z^}g|yFWqt9cfWPbmp}K}SG?fIUiS0jQm6g$l^xmSQ6roR4*pX6#6nGmM%z*Cl z3TJM;HooGj3-GQeosUx)MFG)(x}y0w{8)4(~7%MB~#Uv9B!0ec!UDwe3gtzl$SUkwsa{a%|^z)M-FlQjd!Aw8q>{5 zyf-+R(;MGJ*(uRF9nE+tMc8_~OFfciiqsNY7*v)J>u{mGDM3ag6BBfMEyUEt)U~F+ zG)J>OhVz16zr*r!j+GHR&e_hUb#)9u=tc~uepR2yyAw=x=v+sJ>%?kTz|hr51aA0V zLr;8y6sMu}#m;>rOLc8uz8%&cF}*S`8SoE1FlSwDb|B_Dp@UvYh-$upk&JpRjDevR71 z1PhCcquRw|tstB$1X-H0Yu7G5_qi|fm9KoAJHB@>S-t+gXkv_q_CBb;`_1crVcQwo zNRuj2%2H~z8gZmZvY4!%obYHgGmI8xDNB-Aamgi@#{gcM!kL^#Bc;}?W4%KvNtUIg zNkW{YWVIT#%Ba`Pu4j679pC-dXF0O}L1tz)hnawBttzp*An96`;bK&ttfJ+v#*-B_ zRZ4-gVJd*q0k(T+=YIM|Fg`v(lBF0Gv*+%w)4t=&GbXen{N6!mJ38P@RvkAPnlmNYKFkV=I2?B!6D5yDIGg3^XDB(W0M(v1eucRC#!6BAr;*+ooFHTj3X z|0tjR!e@B?3tr6mmp_p|{?p&%uG?;PGc(hVtIHvW$(@vf(pZijpX2z#Joi8F5LZ3v zi61@d!V9|dx#tU?|Ce7F^m~j=PLN~?NtO_&DM^-+XhkG7ky4{atRi$IO6MhUTqDh5 z4G<-�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 As{jB1 literal 0 HcmV?d00001 diff --git a/resources/icons/printers/PrusaResearch_SL1.png b/resources/icons/printers/PrusaResearch_SL1.png new file mode 100644 index 0000000000000000000000000000000000000000..281d7a62026fa00c912eee93650f290c9bc8bdf4 GIT binary patch literal 41541 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 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +support_material_extruder = 5 +support_material_interface_extruder = 5 +perimeter_speed = 40 +solid_infill_speed = 40 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 30 + +[print:0.15mm OPTIMAL MK3 SOLUBLE INTERFACE] +inherits = 0.15mm OPTIMAL MK3 SOLUBLE FULL +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +support_material_extruder = 0 +support_material_interface_layers = 3 +support_material_with_sheath = 0 + [print:0.15mm OPTIMAL SOLUBLE FULL] inherits = *0.15mm*; *soluble_support* -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1 external_perimeter_speed = 25 notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder perimeter_speed = 40 solid_infill_speed = 40 top_infill_extrusion_width = 0.45 top_solid_infill_speed = 30 -wipe_tower = 1 [print:0.15mm OPTIMAL SOLUBLE INTERFACE] inherits = 0.15mm OPTIMAL SOLUBLE FULL @@ -404,6 +428,7 @@ max_print_speed = 200 perimeter_speed = 45 solid_infill_speed = 200 top_solid_infill_speed = 50 + [print:*0.20mm*] inherits = *common* bottom_solid_layers = 4 @@ -436,7 +461,7 @@ top_solid_infill_speed = 50 [print:0.20mm 100mms Linear Advance] inherits = *0.20mm* -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 external_perimeter_speed = 50 infill_speed = 100 max_print_speed = 150 @@ -458,9 +483,27 @@ perimeter_speed = 45 solid_infill_speed = 200 top_solid_infill_speed = 50 +[print:0.20mm FAST MK3 SOLUBLE FULL] +inherits = 0.20mm FAST MK3; *soluble_support* +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +support_material_extruder = 5 +support_material_interface_extruder = 5 +perimeter_speed = 40 +solid_infill_speed = 40 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 30 + +[print:0.20mm FAST MK3 SOLUBLE INTERFACE] +inherits = 0.20mm FAST MK3 SOLUBLE FULL +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +support_material_extruder = 0 +support_material_interface_layers = 3 +support_material_with_sheath = 0 + [print:0.20mm NORMAL] inherits = *0.20mm* -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 [print:0.20mm NORMAL 0.6 nozzle] inherits = *0.20mm*; *0.6nozzle* @@ -468,7 +511,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and [print:0.20mm NORMAL SOLUBLE FULL] inherits = *0.20mm*; *soluble_support* -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1 external_perimeter_speed = 30 notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder perimeter_speed = 40 @@ -519,7 +562,7 @@ top_solid_layers = 4 [print:0.35mm FAST] inherits = *0.35mm* bridge_flow_ratio = 0.95 -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 first_layer_extrusion_width = 0.42 perimeter_extrusion_width = 0.43 solid_infill_extrusion_width = 0.7 @@ -547,6 +590,53 @@ support_material_interface_layers = 2 support_material_with_sheath = 0 support_material_xy_spacing = 150% +# XXXXXXXXXXXXXXXXXXXXXX +# XXX----- MK2.5 ----XXX +# XXXXXXXXXXXXXXXXXXXXXX + +[print:0.15mm 100mms Linear Advance MK2.5] +inherits = 0.15mm 100mms Linear Advance +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 +single_extruder_multi_material_priming = 0 + +[print:0.15mm OPTIMAL MK2.5] +inherits = 0.15mm OPTIMAL +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 +single_extruder_multi_material_priming = 0 + +[print:0.15mm OPTIMAL SOLUBLE FULL MK2.5] +inherits = 0.15mm OPTIMAL SOLUBLE FULL +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 + +[print:0.15mm OPTIMAL SOLUBLE INTERFACE MK2.5] +inherits = 0.15mm OPTIMAL SOLUBLE INTERFACE +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 + +[print:0.20mm 100mms Linear Advance MK2.5] +inherits = 0.20mm 100mms Linear Advance +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 +single_extruder_multi_material_priming = 0 + +[print:0.20mm NORMAL MK2.5] +inherits = 0.20mm NORMAL +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 +single_extruder_multi_material_priming = 0 + +[print:0.20mm NORMAL SOLUBLE FULL MK2.5] +inherits = 0.20mm NORMAL SOLUBLE FULL +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +single_extruder_multi_material_priming = 0 + +[print:0.20mm NORMAL SOLUBLE INTERFACE MK2.5] +inherits = 0.20mm NORMAL SOLUBLE INTERFACE +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +single_extruder_multi_material_priming = 0 + +[print:0.35mm FAST MK2.5] +inherits = 0.35mm FAST +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 +single_extruder_multi_material_priming = 0 + # XXXXXXxxXXXXXXXXXXXXXX # XXX--- filament ---XXX # XXXXXXXXxxXXXXXXXXXXXX @@ -555,7 +645,7 @@ support_material_xy_spacing = 150% cooling = 1 compatible_printers = # For now, all but selected filaments are disabled for the MMU 2.0 -compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) +compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) end_filament_gcode = "; Filament-specific end gcode" extrusion_multiplier = 1 filament_loading_speed = 28 @@ -655,7 +745,7 @@ temperature = 240 [filament:ColorFabb Brass Bronze] inherits = *PLA* # For now, all but selected filaments are disabled for the MMU 2.0 -compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) extrusion_multiplier = 1.2 filament_cost = 80.65 filament_density = 4 @@ -687,7 +777,7 @@ filament_density = 1.24 [filament:ColorFabb Woodfil] inherits = *PLA* # For now, all but selected filaments are disabled for the MMU 2.0 -compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) extrusion_multiplier = 1.2 filament_cost = 62.9 filament_density = 1.15 @@ -789,7 +879,7 @@ temperature = 275 [filament:Fillamentum Timberfil] inherits = *PLA* # For now, all but selected filaments are disabled for the MMU 2.0 -compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) +compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) extrusion_multiplier = 1.2 filament_cost = 68 filament_density = 1.15 @@ -851,7 +941,7 @@ filament_notes = "List of materials tested with standart ABS print settings for [filament:*ABS MMU2*] inherits = Prusa ABS -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material filament_cooling_final_speed = 50 filament_cooling_initial_speed = 10 filament_cooling_moves = 5 @@ -889,7 +979,7 @@ filament_notes = "List of manufacturers tested with standart PET print settings [filament:*PET MMU2*] inherits = Prusa PET -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material temperature = 230 first_layer_temperature = 230 filament_cooling_final_speed = 1 @@ -915,9 +1005,16 @@ filament_cost = 25.4 filament_density = 1.24 filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +[filament:Prusament PLA] +inherits = *PLA* +temperature = 215 +filament_cost = 24.99 +filament_density = 1.24 +filament_notes = "Affordable filament for everyday printing in premium quality manufactured in-house by Josef Prusa" + [filament:*PLA MMU2*] inherits = Prusa PLA -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material temperature = 205 filament_cooling_final_speed = 1 filament_cooling_initial_speed = 2 @@ -934,6 +1031,9 @@ inherits = *PLA MMU2* [filament:Prusa PLA MMU2] inherits = *PLA MMU2* +[filament:Prusament PLA MMU2] +inherits = *PLA MMU2* + [filament:SemiFlex or Flexfill 98A] inherits = *FLEX* filament_cost = 82 @@ -998,7 +1098,7 @@ temperature = 210 [filament:Verbatim BVOH MMU2] inherits = Verbatim BVOH -compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material temperature = 195 filament_notes = BVOH fan_always_on = 1 @@ -1037,7 +1137,22 @@ min_fan_speed = 100 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 220 +[sla_material:*common*] +layer_height = 0.05 +initial_layer_height = 0.3 +exposure_time = 10 +initial_exposure_time = 15 +material_correction_printing = 1, 1, 1 +material_correction_curing = 1, 1, 1 + +[sla_material:Material 1] +inherits = *common* + +[sla_material:Material 2] +inherits = *common* + [printer:*common*] +printer_technology = FFF bed_shape = 0x0,250x0,250x210,0x210 before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n\n between_objects_gcode = @@ -1098,7 +1213,7 @@ z_offset = 0 printer_model = MK2S printer_variant = 0.4 default_print_profile = 0.15mm OPTIMAL -default_filament_profile = Prusa PLA +default_filament_profile = Prusament PLA [printer:*multimaterial*] inherits = *common* @@ -1193,19 +1308,83 @@ default_print_profile = 0.20mm NORMAL 0.6 nozzle inherits = Original Prusa i3 MK2 printer_model = MK2.5 remaining_times = 1 -start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M115 U3.4.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 + +[printer:Original Prusa i3 MK2.5 MMU2 Single] +inherits = Original Prusa i3 MK2.5; *mm2* +printer_model = MK2.5MMU2 +single_extruder_multi_material = 0 +max_print_height = 200 +remaining_times = 1 +silent_mode = 0 +retract_lift_below = 199 +machine_max_acceleration_e = 10000 +machine_max_acceleration_extruding = 2000 +machine_max_acceleration_retracting = 1500 +machine_max_acceleration_x = 9000 +machine_max_acceleration_y = 9000 +machine_max_acceleration_z = 500 +machine_max_feedrate_e = 120 +machine_max_feedrate_x = 500 +machine_max_feedrate_y = 500 +machine_max_feedrate_z = 12 +machine_max_jerk_e = 2.5 +machine_max_jerk_x = 10 +machine_max_jerk_y = 10 +machine_max_jerk_z = 0.2 +machine_min_extruding_rate = 0 +machine_min_travel_rate = 0 +default_print_profile = 0.15mm OPTIMAL MK2.5 +default_filament_profile = Prusament PLA +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n +start_gcode = M107\nM115 U3.4.2 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT?\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors + +[printer:Original Prusa i3 MK2.5 MMU2] +inherits = Original Prusa i3 MK2.5; *mm2* +printer_model = MK2.5MMU2 +max_print_height = 200 +remaining_times = 1 +silent_mode = 0 +retract_lift_below = 199 +machine_max_acceleration_e = 10000 +machine_max_acceleration_extruding = 2000 +machine_max_acceleration_retracting = 1500 +machine_max_acceleration_x = 9000 +machine_max_acceleration_y = 9000 +machine_max_acceleration_z = 500 +machine_max_feedrate_e = 120 +machine_max_feedrate_x = 500 +machine_max_feedrate_y = 500 +machine_max_feedrate_z = 12 +machine_max_jerk_e = 2.5 +machine_max_jerk_x = 10 +machine_max_jerk_y = 10 +machine_max_jerk_z = 0.2 +machine_min_extruding_rate = 0 +machine_min_travel_rate = 0 +default_print_profile = 0.15mm OPTIMAL MK2.5 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n +single_extruder_multi_material = 1 +# The 5x nozzle diameter defines the number of extruders. Other extruder parameters +# (for example the retract values) are duplicaed from the first value, so they do not need +# to be defined explicitely. +nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 +extruder_colour = #FF8000;#0080FF;#00FFFF;#FF4F4F;#9FFF9F +start_gcode = M107\nM115 U3.4.2 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n [printer:Original Prusa i3 MK2.5 0.25 nozzle] inherits = Original Prusa i3 MK2 0.25 nozzle printer_model = MK2.5 remaining_times = 1 -start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M115 U3.4.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.6 nozzle] inherits = Original Prusa i3 MK2 0.6 nozzle printer_model = MK2.5 remaining_times = 1 -start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M115 U3.4.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 # XXXXXXXXXXXXXXXXX # XXX--- MK3 ---XXX @@ -1221,8 +1400,8 @@ machine_max_acceleration_x = 1000,960 machine_max_acceleration_y = 1000,960 machine_max_acceleration_z = 1000,1000 machine_max_feedrate_e = 120,120 -machine_max_feedrate_x = 200,172 -machine_max_feedrate_y = 200,172 +machine_max_feedrate_x = 200,100 +machine_max_feedrate_y = 200,100 machine_max_feedrate_z = 12,12 machine_max_jerk_e = 1.5,1.5 machine_max_jerk_x = 8,8 @@ -1235,7 +1414,7 @@ remaining_times = 1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n retract_lift_below = 209 max_print_height = 210 -start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +start_gcode = M115 U3.4.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} printer_model = MK3 default_print_profile = 0.15mm OPTIMAL MK3 @@ -1265,11 +1444,12 @@ retract_length_toolchange = 3 extra_loading_move = -13 printer_model = MK3MMU2 default_print_profile = 0.15mm OPTIMAL MK3 -default_filament_profile = Prusa PLA MMU2 +default_filament_profile = Prusament PLA MMU2 [printer:Original Prusa i3 MK3 MMU2 Single] inherits = *mm2* -start_gcode = M107\nM115 U3.4.0-RC2 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT?\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +single_extruder_multi_material = 0 +start_gcode = M107\nM115 U3.4.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT?\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK3 MMU2] @@ -1280,9 +1460,27 @@ inherits = *mm2* machine_max_acceleration_e = 8000,8000 nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#0080FF;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M107\nM115 U3.4.0-RC2 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +start_gcode = M107\nM115 U3.4.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n +[printer:Original Prusa SL1] +printer_technology = SLA +printer_model = SL1 +printer_variant = default +default_sla_material_profile = Material 1 +bed_shape = 0x0,150x0,150x100,0x100 +max_print_height = 100 +display_width = 150 +display_height = 100 +display_pixels_x = 2000 +display_pixels_y = 1000 +printer_correction = 1,1,1 + +[printer:Original Prusa SL1 dummy] +inherits = Original Prusa SL1 +printer_variant = dummy +default_sla_material_profile = Material 2 + # The obsolete presets will be removed when upgrading from the legacy configuration structure (up to Slic3r 1.39.2) to 1.40.0 and newer. [obsolete_presets] print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3";"print:0.15mm OPTIMAL MK3 MMU2";"print:0.20mm FAST MK3 MMU2" diff --git a/slic3r.sublime-project b/slic3r.sublime-project index 3f2fc36dc2..785dddba41 100644 --- a/slic3r.sublime-project +++ b/slic3r.sublime-project @@ -76,7 +76,7 @@ { "path": ".", // "folder_exclude_patterns": [".svn", "._d", ".metadata", ".settings"], - "file_exclude_patterns": ["XS.c"] + "file_exclude_patterns": ["XS.c", "*.pch", "*.ilk", "*.js" ] } ], diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 4deafbdafb..fb42a85ae8 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -1276,8 +1276,11 @@ public: void read_cli(const std::vector &tokens, t_config_option_keys* extra); bool read_cli(int argc, char** argv, t_config_option_keys* extra); -private: typedef std::map t_options_map; + t_options_map::const_iterator cbegin() const { return options.cbegin(); } + t_options_map::const_iterator cend() const { return options.cend(); } + +private: t_options_map options; }; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c4d0c1bd93..52bdf1d1b0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1652,8 +1652,8 @@ void GCode::append_full_config(const Print& print, std::string& str) } const DynamicConfig &full_config = print.placeholder_parser().config(); for (const char *key : { - "print_settings_id", "filament_settings_id", "printer_settings_id", - "printer_model", "printer_variant", "default_print_profile", "default_filament_profile", + "print_settings_id", "filament_settings_id", "sla_material_settings_id", "printer_settings_id", + "printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_material_profile", "compatible_printers_condition_cummulative", "inherits_cummulative" }) { const ConfigOption *opt = full_config.option(key); if (opt != nullptr) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 514cc0e0f9..2d3343c635 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -495,7 +495,7 @@ public: }; CancelStatus cancel_status() const { return m_cancel_status; } // Has the calculation been canceled? - bool canceled() const { return m_cancel_status; } + bool canceled() const { return m_cancel_status != NOT_CANCELED; } // Cancel the running computation. Stop execution of all the background threads. void cancel() { m_cancel_status = CANCELED_BY_USER; } void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; } diff --git a/src/slic3r/Config/Snapshot.cpp b/src/slic3r/Config/Snapshot.cpp index 704fbcfa1b..e92c829c0a 100644 --- a/src/slic3r/Config/Snapshot.cpp +++ b/src/slic3r/Config/Snapshot.cpp @@ -406,7 +406,7 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot: cfg.version.min_slic3r_version = it->min_slic3r_version; cfg.version.max_slic3r_version = it->max_slic3r_version; } - } catch (const std::runtime_error &err) { + } catch (const std::runtime_error & /* err */) { } snapshot.vendor_configs.emplace_back(std::move(cfg)); } @@ -521,7 +521,7 @@ SnapshotDB& SnapshotDB::singleton() // Update the min / max slic3r versions compatible with the configurations stored inside the snapshots // based on the min / max slic3r versions defined by the vendor specific config indices. instance.update_slic3r_versions(index_db); - } catch (std::exception &ex) { + } catch (std::exception & /* ex */) { } } return instance; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index ce65acd5f4..f2b07c51ec 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -74,7 +74,7 @@ void BackgroundSlicingProcess::thread_proc() this->set_step_done(bspsGCodeFinalize); } } - } catch (CanceledException &ex) { + } catch (CanceledException & /* ex */) { // Canceled, this is all right. assert(m_print->canceled()); } catch (std::exception &ex) { diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 407da7ae39..656e0847fc 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -234,13 +234,13 @@ void BedShapePanel::update_shape() Vec2d rect_origin(Vec2d::Zero()); try{ rect_size = boost::any_cast(m_optgroups[SHAPE_RECTANGULAR]->get_value("rect_size")); } - catch (const std::exception &e){ + catch (const std::exception & /* e */){ return; } try{ rect_origin = boost::any_cast(m_optgroups[SHAPE_RECTANGULAR]->get_value("rect_origin")); } - catch (const std::exception &e){ + catch (const std::exception & /* e */){ return;} auto x = rect_size(0); @@ -269,7 +269,7 @@ void BedShapePanel::update_shape() try{ diameter = boost::any_cast(m_optgroups[SHAPE_CIRCULAR]->get_value("diameter")); } - catch (const std::exception &e){ + catch (const std::exception & /* e */){ return; } if (diameter == 0.0) return ; diff --git a/src/slic3r/GUI/ConfigWizard.hpp b/src/slic3r/GUI/ConfigWizard.hpp index 73fce7cd21..6ac1bcbd84 100644 --- a/src/slic3r/GUI/ConfigWizard.hpp +++ b/src/slic3r/GUI/ConfigWizard.hpp @@ -39,7 +39,7 @@ private: struct priv; std::unique_ptr p; - friend class ConfigWizardPage; + friend struct ConfigWizardPage; }; diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 9e18cac020..1a21f8a9ff 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -68,7 +68,7 @@ void enable_screensaver() bool debugged() { #ifdef _WIN32 - return IsDebuggerPresent(); + return IsDebuggerPresent() == TRUE; #else return false; #endif /* _WIN32 */ @@ -233,7 +233,7 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt break; } } - catch (const std::exception &e) + catch (const std::exception & /* e */) { int i = 0;//no reason, just experiment } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a40bf44386..ae39c125c1 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -91,7 +91,7 @@ bool GUI_App::OnInit() load_language(); // Suppress the '- default -' presets. - preset_bundle->set_default_suppressed(app_config->get("no_defaults").empty() ? false : true); + preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1"); // eval{ preset_bundle->load_presets(*app_config); // }; @@ -601,8 +601,9 @@ void GUI_App::add_config_menu(wxMenuBar *menu) bool GUI_App::check_unsaved_changes() { std::string dirty; + PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology(); for (Tab *tab : tabs_list) - if (tab->current_preset_is_dirty()) + if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty()) if (dirty.empty()) dirty = tab->name(); else @@ -636,9 +637,10 @@ void GUI_App::delete_tab_from_list(Tab* tab) // Update UI / Tabs to reflect changes in the currently loaded presets void GUI_App::load_current_presets() { - for (Tab *tab : tabs_list) { - tab->load_current_preset(); - } + PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology(); + for (Tab *tab : tabs_list) + if (tab->supports_printer_technology(printer_technology)) + tab->load_current_preset(); } Sidebar& GUI_App::sidebar() diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 59ebe10b23..29b2b8eecf 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -418,7 +418,7 @@ struct Sidebar::priv void Sidebar::priv::show_preset_comboboxes() { - const bool showSLA = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA; + const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; wxWindowUpdateLocker noUpdates(wxGetApp().mainframe); @@ -562,40 +562,49 @@ void Sidebar::remove_unused_filament_combos(const int current_extruder_count) void Sidebar::update_presets(Preset::Type preset_type) { + PresetBundle &preset_bundle = *wxGetApp().preset_bundle; + switch (preset_type) { case Preset::TYPE_FILAMENT: if (p->combos_filament.size() == 1) { // Single filament printer, synchronize the filament presets. - const std::string &name = wxGetApp().preset_bundle->filaments.get_selected_preset().name; - wxGetApp().preset_bundle->set_filament_preset(0, name); + const std::string &name = preset_bundle.filaments.get_selected_preset().name; + preset_bundle.set_filament_preset(0, name); } for (size_t i = 0; i < p->combos_filament.size(); i++) { - wxGetApp().preset_bundle->update_platter_filament_ui(i, p->combos_filament[i]); + preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]); } break; case Preset::TYPE_PRINT: - wxGetApp().preset_bundle->prints.update_platter_ui(p->combo_print); + preset_bundle.prints.update_platter_ui(p->combo_print); break; case Preset::TYPE_SLA_MATERIAL: - wxGetApp().preset_bundle->sla_materials.update_platter_ui(p->combo_sla_material); + preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material); break; - case Preset::TYPE_PRINTER: - // Update the print choosers to only contain the compatible presets, update the dirty flags. - wxGetApp().preset_bundle->prints.update_platter_ui(p->combo_print); - // Update the printer choosers, update the dirty flags. - wxGetApp().preset_bundle->printers.update_platter_ui(p->combo_printer); - // Update the filament choosers to only contain the compatible presets, update the color preview, - // update the dirty flags. - for (size_t i = 0; i < p->combos_filament.size(); i++) { - wxGetApp().preset_bundle->update_platter_filament_ui(i, p->combos_filament[i]); - } - p->show_preset_comboboxes(); - break; + case Preset::TYPE_PRINTER: + { + PrinterTechnology printer_technology = preset_bundle.printers.get_edited_preset().printer_technology(); + // Update the print choosers to only contain the compatible presets, update the dirty flags. + if (printer_technology == ptFFF) + preset_bundle.prints.update_platter_ui(p->combo_print); + else + preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material); + // Update the printer choosers, update the dirty flags. + preset_bundle.printers.update_platter_ui(p->combo_printer); + // Update the filament choosers to only contain the compatible presets, update the color preview, + // update the dirty flags. + if (printer_technology == ptFFF) { + for (size_t i = 0; i < p->combos_filament.size(); ++ i) + preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]); + } + p->show_preset_comboboxes(); + break; + } default: break; } diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 07410e325f..6aa255612b 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -210,23 +210,20 @@ void Preset::normalize(DynamicPrintConfig &config) } } -DynamicPrintConfig& Preset::load(const std::vector &keys, const StaticPrintConfig &defaults) +std::string Preset::remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config) { - // Set the configuration from the defaults. - this->config.apply_only(defaults, keys.empty() ? defaults.keys() : keys); - if (! this->is_default) { - // Load the preset file, apply preset values on top of defaults. - try { - this->config.load_from_ini(this->file); - Preset::normalize(this->config); - } catch (const std::ifstream::failure &err) { - throw std::runtime_error(std::string("The selected preset cannot be loaded: ") + this->file + "\n\tReason: " + err.what()); - } catch (const std::runtime_error &err) { - throw std::runtime_error(std::string("Failed loading the preset file: ") + this->file + "\n\tReason: " + err.what()); + std::string incorrect_keys; + for (const std::string &key : config.keys()) + if (! default_config.has(key)) { + if (incorrect_keys.empty()) + incorrect_keys = key; + else { + incorrect_keys += ", "; + incorrect_keys += key; + } + config.erase(key); } - } - this->loaded = true; - return this->config; + return incorrect_keys; } void Preset::save() @@ -390,6 +387,7 @@ const std::vector& Preset::sla_material_options() "exposure_time", "initial_exposure_time", "material_correction_printing", "material_correction_curing", "material_notes", + "default_sla_material_profile", "compatible_printers", "compatible_printers_condition", "inherits" }; @@ -436,7 +434,8 @@ void PresetCollection::add_default_preset(const std::vector &keys, { // Insert just the default preset. m_presets.emplace_back(Preset(this->type(), preset_name, true)); - m_presets.back().load(keys, defaults); + m_presets.back().config.apply_only(defaults, keys.empty() ? defaults.keys() : keys); + m_presets.back().loaded = true; ++ m_num_default_presets; } @@ -446,7 +445,6 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri { boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred(); m_dir_path = dir.string(); - t_config_option_keys keys = this->default_preset().config.keys(); std::string errors_cummulative; for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini")) { @@ -462,8 +460,26 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri try { Preset preset(m_type, name, false); preset.file = dir_entry.path().string(); - //FIXME One should initialize with SLAFullPrintConfig for the SLA profiles! - preset.load(keys, static_cast(FullPrintConfig::defaults())); + // Load the preset file, apply preset values on top of defaults. + try { + DynamicPrintConfig config; + config.load_from_ini(preset.file); + // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. + const Preset &default_preset = this->default_preset_for(config); + preset.config = default_preset.config; + preset.config.apply(std::move(config)); + Preset::normalize(preset.config); + // Report configuration fields, which are misplaced into a wrong group. + std::string incorrect_keys = Preset::remove_invalid_keys(config, default_preset.config); + if (! incorrect_keys.empty()) + BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << + preset.file << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed"; + preset.loaded = true; + } catch (const std::ifstream::failure &err) { + throw std::runtime_error(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what()); + } catch (const std::runtime_error &err) { + throw std::runtime_error(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what()); + } m_presets.emplace_back(preset); } catch (const std::runtime_error &err) { errors_cummulative += err.what(); @@ -491,8 +507,8 @@ static bool profile_print_params_same(const DynamicPrintConfig &cfg1, const Dyna // Following keys are used by the UI, not by the slicing core, therefore they are not important // when comparing profiles for equality. Ignore them. for (const char *key : { "compatible_printers", "compatible_printers_condition", "inherits", - "print_settings_id", "filament_settings_id", "printer_settings_id", - "printer_model", "printer_variant", "default_print_profile", "default_filament_profile" }) + "print_settings_id", "filament_settings_id", "sla_material_settings_id", "printer_settings_id", + "printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_material_profile" }) diff.erase(std::remove(diff.begin(), diff.end(), key), diff.end()); // Preset with the same name as stored inside the config exists. return diff.empty(); @@ -718,7 +734,7 @@ size_t PresetCollection::update_compatible_with_printer_internal(const Preset &a Preset &preset_edited = selected ? m_edited_preset : preset_selected; if (! preset_edited.update_compatible_with_printer(active_printer, &config) && selected && unselect_if_incompatible) - m_idx_selected = (size_t)-1; + m_idx_selected = -1; if (selected) preset_selected.is_compatible = preset_edited.is_compatible; } @@ -1018,4 +1034,10 @@ std::string PresetCollection::path_from_name(const std::string &new_name) const return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string(); } +const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const +{ + const ConfigOptionEnumGeneric *opt_printer_technology = config.opt("printer_technology"); + return this->default_preset((opt_printer_technology == nullptr || opt_printer_technology->value == 0) ? 0 : 1); +} + } // namespace Slic3r diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 2d56e96c2d..96c313b1b6 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -125,9 +125,6 @@ public: // Configuration data, loaded from a file, or set from the defaults. DynamicPrintConfig config; - // Load this profile for the following keys only. - DynamicPrintConfig& load(const std::vector &keys, const StaticPrintConfig &defaults); - void save(); // Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty. @@ -177,8 +174,10 @@ public: static const std::vector& sla_printer_options(); static const std::vector& sla_material_options(); - static void update_suffix_modified(); - static void normalize(DynamicPrintConfig &config); + static void update_suffix_modified(); + static void normalize(DynamicPrintConfig &config); + // Report configuration fields, which are misplaced into a wrong group, remove them from the config. + static std::string remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config); protected: friend class PresetCollection; @@ -200,9 +199,11 @@ public: typedef std::deque::iterator Iterator; typedef std::deque::const_iterator ConstIterator; Iterator begin() { return m_presets.begin() + m_num_default_presets; } - ConstIterator begin() const { return m_presets.begin() + m_num_default_presets; } + ConstIterator begin() const { return m_presets.cbegin() + m_num_default_presets; } + ConstIterator cbegin() const { return m_presets.cbegin() + m_num_default_presets; } Iterator end() { return m_presets.end(); } - ConstIterator end() const { return m_presets.end(); } + ConstIterator end() const { return m_presets.cend(); } + ConstIterator cend() const { return m_presets.cend(); } void reset(bool delete_files); @@ -279,8 +280,9 @@ public: static const std::string& get_suffix_modified(); // Return a preset possibly with modifications. - Preset& default_preset() { return m_presets.front(); } - const Preset& default_preset() const { return m_presets.front(); } + Preset& default_preset(size_t idx = 0) { assert(idx < m_num_default_presets); return m_presets[idx]; } + const Preset& default_preset(size_t idx = 0) const { assert(idx < m_num_default_presets); return m_presets[idx]; } + virtual const Preset& default_preset_for(const DynamicPrintConfig & /* config */) const { return this->default_preset(); } // Return a preset by an index. If the preset is active, a temporary copy is returned. Preset& preset(size_t idx) { return (int(idx) == m_idx_selected) ? m_edited_preset : m_presets[idx]; } const Preset& preset(size_t idx) const { return const_cast(this)->preset(idx); } @@ -440,6 +442,16 @@ private: friend class PresetBundle; }; +// Printer supports the FFF and SLA technologies, with different set of configuration values, +// therefore this PresetCollection needs to handle two defaults. +class PrinterPresetCollection : public PresetCollection +{ +public: + PrinterPresetCollection(Preset::Type type, const std::vector &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name = "- default -") : + PresetCollection(type, keys, defaults, default_name) {} + const Preset& default_preset_for(const DynamicPrintConfig &config) const override; +}; + } // namespace Slic3r #endif /* slic3r_Preset_hpp_ */ diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index f0f53ff6cc..0bd7d2e158 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -79,13 +79,17 @@ PresetBundle::PresetBundle() : this->printers.preset(1).printer_technology() = ptSLA; for (size_t i = 0; i < 2; ++ i) { // The following ugly switch is to avoid printers.preset(0) to return the edited instance, as the 0th default is the current one. - Preset &preset = (i == 0) ? this->printers.default_preset() : this->printers.preset(1); + Preset &preset = this->printers.default_preset(i); preset.config.optptr("printer_settings_id", true); preset.config.optptr("printer_vendor", true); preset.config.optptr("printer_model", true); preset.config.optptr("printer_variant", true); - preset.config.optptr("default_print_profile", true); - preset.config.option("default_filament_profile", true)->values = { "" }; + if (i == 0) { + preset.config.optptr("default_print_profile", true); + preset.config.option("default_filament_profile", true)->values = { "" }; + } else + preset.config.optptr("default_sla_material_profile", true); + // default_sla_material_profile preset.inherits(); } @@ -315,7 +319,7 @@ void PresetBundle::load_selections(const AppConfig &config) sla_materials.select_preset_by_name_strict(initial_sla_material_profile_name); printers.select_preset_by_name(initial_printer_profile_name, true); - if (printers.get_selected_preset().printer_technology() == ptFFF){ + if (printers.get_selected_preset().printer_technology() == ptFFF) { // Load the names of the other filament profiles selected for a multi-material printer. auto *nozzle_diameter = dynamic_cast(printers.get_selected_preset().config.option("nozzle_diameter")); size_t num_extruders = nozzle_diameter->values.size(); @@ -342,8 +346,8 @@ void PresetBundle::load_selections(const AppConfig &config) // Export selections (current print, current filaments, current printer) into config.ini void PresetBundle::export_selections(AppConfig &config) { - assert(filament_presets.size() >= 1); - assert(filament_presets.size() > 1 || filaments.get_selected_preset_name() == filament_presets.front()); + assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() >= 1); + assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() > 1 || filaments.get_selected_preset_name() == filament_presets.front()); config.clear_section("presets"); config.set("presets", "print", prints.get_selected_preset_name()); config.set("presets", "filament", filament_presets.front()); @@ -975,7 +979,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla } else if (boost::starts_with(section.first, "sla_material:")) { presets = &this->sla_materials; loaded = &loaded_sla_materials; - preset_name = section.first.substr(9); + preset_name = section.first.substr(13); } else if (boost::starts_with(section.first, "printer:")) { presets = &this->printers; loaded = &loaded_printers; @@ -1025,25 +1029,25 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla continue; if (presets != nullptr) { // Load the print, filament or printer preset. - const DynamicPrintConfig &default_config = presets->default_preset().config; - DynamicPrintConfig config(default_config); - for (auto &kvp : section.second) - config.set_deserialize(kvp.first, kvp.second.data()); + const DynamicPrintConfig *default_config = nullptr; + DynamicPrintConfig config; + if (presets == &this->printers) { + // Select the default config based on the printer_technology field extracted from kvp. + DynamicPrintConfig config_src; + for (auto &kvp : section.second) + config_src.set_deserialize(kvp.first, kvp.second.data()); + default_config = &presets->default_preset_for(config_src).config; + config = *default_config; + config.apply(config_src); + } else { + default_config = &presets->default_preset().config; + config = *default_config; + for (auto &kvp : section.second) + config.set_deserialize(kvp.first, kvp.second.data()); + } Preset::normalize(config); // Report configuration fields, which are misplaced into a wrong group. - std::string incorrect_keys; - size_t n_incorrect_keys = 0; - for (const std::string &key : config.keys()) - if (! default_config.has(key)) { - if (incorrect_keys.empty()) - incorrect_keys = key; - else { - incorrect_keys += ", "; - incorrect_keys += key; - } - config.erase(key); - ++ n_incorrect_keys; - } + std::string incorrect_keys = Preset::remove_invalid_keys(config, *default_config); if (! incorrect_keys.empty()) BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << section.first << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed"; @@ -1207,12 +1211,11 @@ void PresetBundle::update_compatible_with_printer(bool select_other_if_incompati } case ptSLA: { - const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile"); - const std::vector &prefered_filament_profiles = printer_preset.config.option("default_filament_profile")->values; - prefered_print_profile.empty() ? + const std::string &prefered_sla_material_profile = printer_preset.config.opt_string("default_sla_material_profile"); + prefered_sla_material_profile.empty() ? this->sla_materials.update_compatible_with_printer(printer_preset, select_other_if_incompatible) : this->sla_materials.update_compatible_with_printer(printer_preset, select_other_if_incompatible, - [&prefered_print_profile](const std::string& profile_name){ return profile_name == prefered_print_profile; }); + [&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; }); } } } diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index e116b0ff90..a7d9ab7d2e 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -41,7 +41,7 @@ public: PresetCollection prints; PresetCollection filaments; PresetCollection sla_materials; - PresetCollection printers; + PrinterPresetCollection printers; // Filament preset names for a multi-extruder or multi-material print. // extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size() std::vector filament_presets; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index bba5161cc3..c19027581d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -627,7 +627,8 @@ void Tab::load_config(const DynamicPrintConfig& config) } // Reload current $self->{config} (aka $self->{presets}->edited_preset->config) into the UI fields. -void Tab::reload_config(){ +void Tab::reload_config() +{ Freeze(); for (auto page : m_pages) page->reload_config(); @@ -787,6 +788,7 @@ void Tab::update_preset_description_line() ", ver: " + parent->vendor->config_version.to_string(); if (name() == "printer"){ const std::string &printer_model = preset.config.opt_string("printer_model"); + //FIXME add prefered_sla_material_profile for SLA const std::string &default_print_profile = preset.config.opt_string("default_print_profile"); const std::vector &default_filament_profiles = preset.config.option("default_filament_profile")->values; if (!printer_model.empty()) @@ -2045,7 +2047,8 @@ void TabPrinter::on_preset_loaded() void TabPrinter::update_pages() { // update m_pages ONLY if printer technology is changed - if (m_presets->get_edited_preset().printer_technology() == m_printer_technology) + const PrinterTechnology new_printer_technology = m_presets->get_edited_preset().printer_technology(); + if (new_printer_technology == m_printer_technology) return; // hide all old pages @@ -2057,7 +2060,8 @@ void TabPrinter::update_pages() // build Tab according to the technology, if it's not exist jet OR // set m_pages_(technology after changing) to m_pages - if (m_presets->get_edited_preset().printer_technology() == ptFFF) + // m_printer_technology will be set by Tab::load_current_preset() + if (new_printer_technology == ptFFF) m_pages_fff.empty() ? build_fff() : m_pages.swap(m_pages_fff); else m_pages_sla.empty() ? build_sla() : m_pages.swap(m_pages_sla); @@ -2207,35 +2211,35 @@ void Tab::load_current_preset() update_tab_ui(); // update show/hide tabs - if (m_name == "printer"){ + if (m_name == "printer") { PrinterTechnology& printer_technology = m_presets->get_edited_preset().printer_technology(); if (printer_technology != static_cast(this)->m_printer_technology) { - for (auto& tab : wxGetApp().mainframe->get_preset_tabs()){ + for (auto& tab : wxGetApp().mainframe->get_preset_tabs()) { if (tab.technology != printer_technology) { int page_id = wxGetApp().tab_panel()->FindPage(tab.panel); wxGetApp().tab_panel()->GetPage(page_id)->Show(false); wxGetApp().tab_panel()->RemovePage(page_id); - } - else + } else wxGetApp().tab_panel()->InsertPage(wxGetApp().tab_panel()->FindPage(this), tab.panel, tab.panel->title()); } - static_cast(this)->m_printer_technology = printer_technology; } - } - - on_presets_changed(); - - if (name() == "print") - update_frequently_changed_parameters(); - if (m_name == "printer"){ - static_cast(this)->m_initial_extruders_count = static_cast(this)->m_extruders_count; - const Preset* parent_preset = m_presets->get_selected_preset_parent(); - static_cast(this)->m_sys_extruders_count = parent_preset == nullptr ? 0 : - static_cast(parent_preset->config.option("nozzle_diameter"))->values.size(); + on_presets_changed(); + if (printer_technology == ptFFF) { + static_cast(this)->m_initial_extruders_count = static_cast(this)->m_extruders_count; + const Preset* parent_preset = m_presets->get_selected_preset_parent(); + static_cast(this)->m_sys_extruders_count = parent_preset == nullptr ? 0 : + static_cast(parent_preset->config.option("nozzle_diameter"))->values.size(); + } } + else { + on_presets_changed(); + if (m_name == "print") + update_frequently_changed_parameters(); + } + m_opt_status_value = (m_presets->get_selected_preset_parent() ? osSystemValue : 0) | osInitValue; init_options_list(); update_changed_ui(); @@ -2543,7 +2547,7 @@ void Tab::delete_preset() // Delete the file and select some other reasonable preset. // The 'external' presets will only be removed from the preset list, their files will not be deleted. try{ m_presets->delete_current_preset(); } - catch (const std::exception &e) + catch (const std::exception & /* e */) { return; } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 1961142563..942a509084 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -213,6 +213,7 @@ public: wxString title() const { return m_title; } std::string name() const { return m_name; } Preset::Type type() const { return m_type; } + virtual bool supports_printer_technology(const PrinterTechnology tech) = 0; void create_preset_tab(); void load_current_preset(); @@ -291,6 +292,7 @@ public: void reload_config() override; void update() override; void OnActivate() override; + bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptFFF; } }; //Slic3r::GUI::Tab::Filament; @@ -308,6 +310,7 @@ public: void reload_config() override; void update() override; void OnActivate() override; + bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptFFF; } }; //Slic3r::GUI::Tab::Printer; @@ -321,9 +324,9 @@ class TabPrinter : public Tab std::vector m_pages_fff; std::vector m_pages_sla; public: - wxButton* m_serial_test_btn; - wxButton* m_print_host_test_btn; - wxButton* m_printhost_browse_btn; + wxButton* m_serial_test_btn = nullptr; + wxButton* m_print_host_test_btn = nullptr; + wxButton* m_printhost_browse_btn = nullptr; size_t m_extruders_count; size_t m_extruders_count_old = 0; @@ -349,6 +352,7 @@ public: void build_extruder_pages(); void on_preset_loaded() override; void init_options_list() override; + bool supports_printer_technology(const PrinterTechnology /* tech */) override { return true; } }; class TabSLAMaterial : public Tab @@ -362,6 +366,7 @@ public: void build() override; void update() override; void init_options_list() override; + bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptSLA; } }; class SavePresetWindow :public wxDialog From 0984c9a111741aabea6ca838ec7931f4023716d5 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 31 Oct 2018 17:29:21 +0100 Subject: [PATCH 03/12] deps: Fix dependency list --- deps/CMakeLists.txt | 9 ++++++++- deps/deps-unix-static.cmake | 1 - 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index b02575617e..eca86a7c5e 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -48,7 +48,14 @@ else () endif() add_custom_target(deps ALL - DEPENDS dep_boost dep_tbb dep_libcurl dep_wxwidgets + DEPENDS + dep_boost + dep_tbb + dep_libcurl + dep_wxwidgets + dep_gtest + dep_nlopt + dep_libpng ) # Note: I'm not using any of the LOG_xxx options in ExternalProject_Add() commands diff --git a/deps/deps-unix-static.cmake b/deps/deps-unix-static.cmake index a9ae1ea6a9..cbba0f14df 100644 --- a/deps/deps-unix-static.cmake +++ b/deps/deps-unix-static.cmake @@ -63,7 +63,6 @@ ExternalProject_Add(dep_zlib INSTALL_COMMAND "" ) - ExternalProject_Add(dep_libpng DEPENDS dep_zlib EXCLUDE_FROM_ALL 1 From 75c097010d8d10d27d4fb48ac0f6562e0784c61a Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 31 Oct 2018 18:05:25 +0100 Subject: [PATCH 04/12] Finished (?) switching between the FDM / SLA profiles, fixed an invalidation bug in Print::apply() --- CMakeLists.txt | 2 +- src/libslic3r/Print.cpp | 9 +++++--- src/libslic3r/Print.hpp | 28 ++++++++++++++++++++++- src/slic3r/GUI/GUI_App.cpp | 7 ++++-- src/slic3r/GUI/PresetBundle.cpp | 17 ++++++++++---- src/slic3r/GUI/Tab.cpp | 40 ++++++++++++++++++++++----------- 6 files changed, 79 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66650857b3..0656b824e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ include_directories(${LIBDIR}/libslic3r ${LIBDIR}/clipper ${LIBDIR}/polypartitio if(WIN32) # BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking. - add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 -D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) endif() add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 88e2972748..3de77b9114 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -983,7 +983,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co update_apply_status(this->invalidate_step(psWipeTower)); if ((*it_old)->print_object->set_copies(new_instances.copies)) { // Invalidated - update_apply_status(this->invalidate_step(psSkirt) || this->invalidate_step(psBrim) || this->invalidate_step(psGCodeExport)); + static PrintStep steps[] = { psSkirt, psBrim, psGCodeExport }; + update_apply_status(this->invalidate_multiple_steps(steps, steps + 3)); } print_objects_new.emplace_back((*it_old)->print_object); const_cast(*it_old)->status = PrintObjectStatus::Reused; @@ -1001,8 +1002,10 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co delete pos.print_object; deleted_objects = true; } - if (deleted_objects) - update_apply_status(this->invalidate_step(psSkirt) || this->invalidate_step(psBrim) || this->invalidate_step(psWipeTower) || this->invalidate_step(psGCodeExport)); + if (deleted_objects) { + static PrintStep steps[] = { psSkirt, psBrim, psWipeTower, psGCodeExport }; + update_apply_status(this->invalidate_multiple_steps(steps, steps + 4)); + } update_apply_status(new_objects); } print_object_status.clear(); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 2d3343c635..dfa5cc4851 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -104,6 +104,28 @@ public: return invalidated; } + template + bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, tbb::mutex &mtx, CancelationCallback cancel) { + bool invalidated = false; + for (StepTypeIterator it = step_begin; ! invalidated && it != step_end; ++ it) + invalidated = m_state[*it].load(std::memory_order_relaxed) != INVALID; + if (invalidated) { +#if 0 + if (mtx.state != mtx.HELD) { + printf("Not held!\n"); + } +#endif + // Raise the mutex, so that the following cancel() callback could cancel + // the background processing. + mtx.unlock(); + cancel(); + for (StepTypeIterator it = step_begin; it != step_end; ++ it) + m_state[*it] = INVALID; + mtx.lock(); + } + return invalidated; + } + // Make all steps invalid. // The provided mutex should be locked at this point, guarding access to m_state. // In case any step has already been entered or finished, cancel the background @@ -245,7 +267,9 @@ public: // methods for handling state bool invalidate_state_by_config_options(const std::vector &opt_keys); bool invalidate_step(PrintObjectStep step); - bool invalidate_all_steps(); + template + bool invalidate_multiple_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, m_mutex, m_cancel_callback); } + bool invalidate_all_steps(); bool is_step_done(PrintObjectStep step) const { return m_state.is_done(step); } // To be used over the layer_height_profile of both the PrintObject and ModelObject @@ -509,6 +533,8 @@ protected: void set_started(PrintStep step) { m_state.set_started(step, m_mutex); throw_if_canceled(); } void set_done(PrintStep step) { m_state.set_done(step, m_mutex); throw_if_canceled(); } bool invalidate_step(PrintStep step); + template + bool invalidate_multiple_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, m_mutex, m_cancel_callback); } bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); } // methods for handling regions diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 416af8089f..1122781243 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -642,8 +642,11 @@ void GUI_App::load_current_presets() { PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology(); for (Tab *tab : tabs_list) - if (tab->supports_printer_technology(printer_technology)) - tab->load_current_preset(); + if (tab->supports_printer_technology(printer_technology)) { + if (tab->name() == "printer") + static_cast(tab)->update_pages(); + tab->load_current_preset(); + } } Sidebar& GUI_App::sidebar() diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 88a56b5d02..f22299b7ca 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -314,10 +314,17 @@ void PresetBundle::load_selections(const AppConfig &config) // If the printer profile enumerated by the config are not visible, select an alternate preset. // Do not select alternate profiles for the print / filament profiles as those presets // will be selected by the following call of this->update_compatible_with_printer(true). - prints.select_preset_by_name_strict(initial_print_profile_name); - filaments.select_preset_by_name_strict(initial_filament_profile_name); - sla_materials.select_preset_by_name_strict(initial_sla_material_profile_name); printers.select_preset_by_name(initial_printer_profile_name, true); + PrinterTechnology printer_technology = printers.get_selected_preset().printer_technology(); + if (printer_technology == ptFFF) { + prints.select_preset_by_name_strict(initial_print_profile_name); + filaments.select_preset_by_name_strict(initial_filament_profile_name); + sla_materials.select_preset_by_name(initial_sla_material_profile_name, true); + } else { + prints.select_preset_by_name(initial_print_profile_name, true); + filaments.select_preset_by_name(initial_filament_profile_name, true); + sla_materials.select_preset_by_name_strict(initial_sla_material_profile_name); + } if (printers.get_selected_preset().printer_technology() == ptFFF) { // Load the names of the other filament profiles selected for a multi-material printer. @@ -1208,6 +1215,7 @@ void PresetBundle::update_compatible_with_printer(bool select_other_if_incompati } } } + break; } case ptSLA: { @@ -1216,7 +1224,8 @@ void PresetBundle::update_compatible_with_printer(bool select_other_if_incompati this->sla_materials.update_compatible_with_printer(printer_preset, select_other_if_incompatible) : this->sla_materials.update_compatible_with_printer(printer_preset, select_other_if_incompatible, [&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; }); - } + break; + } } } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 1b40333f6f..ff681d223f 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -788,22 +788,36 @@ void Tab::update_preset_description_line() description_line += "\t" + _(L("vendor")) + ": " + (name()=="printer" ? "\n\t\t" : "") + parent->vendor->name + ", ver: " + parent->vendor->config_version.to_string(); if (name() == "printer") { - const std::string &printer_model = preset.config.opt_string("printer_model"); - //FIXME add prefered_sla_material_profile for SLA - const std::string &default_print_profile = preset.config.opt_string("default_print_profile"); - const std::vector &default_filament_profiles = preset.config.option("default_filament_profile")->values; - if (!printer_model.empty()) + const std::string &printer_model = preset.config.opt_string("printer_model"); + if (! printer_model.empty()) description_line += "\n\n\t" + _(L("printer model")) + ": \n\t\t" + printer_model; - if (!default_print_profile.empty()) - description_line += "\n\n\t" + _(L("default print profile")) + ": \n\t\t" + default_print_profile; - if (!default_filament_profiles.empty()) + switch (preset.printer_technology()) { + case ptFFF: { - description_line += "\n\n\t" + _(L("default filament profile")) + ": \n\t\t"; - for (auto& profile : default_filament_profiles) { - if (&profile != &*default_filament_profiles.begin()) - description_line += ", "; - description_line += profile; + //FIXME add prefered_sla_material_profile for SLA + const std::string &default_print_profile = preset.config.opt_string("default_print_profile"); + const std::vector &default_filament_profiles = preset.config.option("default_filament_profile")->values; + if (!default_print_profile.empty()) + description_line += "\n\n\t" + _(L("default print profile")) + ": \n\t\t" + default_print_profile; + if (!default_filament_profiles.empty()) + { + description_line += "\n\n\t" + _(L("default filament profile")) + ": \n\t\t"; + for (auto& profile : default_filament_profiles) { + if (&profile != &*default_filament_profiles.begin()) + description_line += ", "; + description_line += profile; + } } + break; + } + case ptSLA: + { + //FIXME add prefered_sla_material_profile for SLA + const std::string &default_sla_material_profile = preset.config.opt_string("default_sla_material_profile"); + if (!default_sla_material_profile.empty()) + description_line += "\n\n\t" + _(L("default SLA material profile")) + ": \n\t\t" + default_sla_material_profile; + break; + } } } } From 90216ac0b402d262e9f64b86185a2bee3ccd27ee Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 31 Oct 2018 18:27:30 +0100 Subject: [PATCH 05/12] ConfigWizard: Fix asserts --- src/slic3r/GUI/ConfigWizard.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index e7b1868d01..ba87cd46a7 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -831,8 +831,8 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) : topsizer->AddSpacer(INDEX_MARGIN); topsizer->Add(p->hscroll, 1, wxEXPAND); - p->btn_prev = new wxButton(this, wxID_NONE, _(L("< &Back"))); - p->btn_next = new wxButton(this, wxID_NONE, _(L("&Next >"))); + p->btn_prev = new wxButton(this, wxID_ANY, _(L("< &Back"))); + p->btn_next = new wxButton(this, wxID_ANY, _(L("&Next >"))); p->btn_finish = new wxButton(this, wxID_APPLY, _(L("&Finish"))); p->btn_cancel = new wxButton(this, wxID_CANCEL); p->btnsizer->AddStretchSpacer(); From e6d78cc0635a257c131d6ff245c6713fe06e523d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 31 Oct 2018 19:21:00 +0100 Subject: [PATCH 06/12] Print step invalidation: Improvement of readability. --- src/libslic3r/Print.cpp | 11 ++++------- src/libslic3r/Print.hpp | 11 ++++++++--- src/libslic3r/PrintObject.cpp | 35 +++++++++++++++++------------------ 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 3de77b9114..770d02a7c6 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -977,14 +977,13 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co new_objects = true; if (it_old != old.end()) const_cast(*it_old)->status = PrintObjectStatus::Deleted; - } else if ((*it_old)->print_object->copies() != new_instances.copies) { + } else { // The PrintObject already exists and the copies differ. if ((*it_old)->print_object->copies().size() != new_instances.copies.size()) update_apply_status(this->invalidate_step(psWipeTower)); if ((*it_old)->print_object->set_copies(new_instances.copies)) { // Invalidated - static PrintStep steps[] = { psSkirt, psBrim, psGCodeExport }; - update_apply_status(this->invalidate_multiple_steps(steps, steps + 3)); + update_apply_status(this->invalidate_steps({ psSkirt, psBrim, psGCodeExport })); } print_objects_new.emplace_back((*it_old)->print_object); const_cast(*it_old)->status = PrintObjectStatus::Reused; @@ -1002,10 +1001,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co delete pos.print_object; deleted_objects = true; } - if (deleted_objects) { - static PrintStep steps[] = { psSkirt, psBrim, psWipeTower, psGCodeExport }; - update_apply_status(this->invalidate_multiple_steps(steps, steps + 4)); - } + if (new_objects || deleted_objects) + update_apply_status(this->invalidate_steps({ psSkirt, psBrim, psWipeTower, psGCodeExport })); update_apply_status(new_objects); } print_object_status.clear(); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index dfa5cc4851..d2dc81755f 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -268,8 +268,9 @@ public: bool invalidate_state_by_config_options(const std::vector &opt_keys); bool invalidate_step(PrintObjectStep step); template - bool invalidate_multiple_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, m_mutex, m_cancel_callback); } - bool invalidate_all_steps(); + bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, this->cancel_mutex(), this->cancel_callback()); } + bool invalidate_steps(std::initializer_list il) { return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_mutex(), this->cancel_callback()); } + bool invalidate_all_steps() { return m_state.invalidate_all(this->cancel_mutex(), this->cancel_callback()); } bool is_step_done(PrintObjectStep step) const { return m_state.is_done(step); } // To be used over the layer_height_profile of both the PrintObject and ModelObject @@ -318,6 +319,9 @@ private: void _generate_support_material(); bool is_printable() const { return ! m_copies.empty(); } + // Implemented in cpp due to cyclic dependencies between Print and PrintObject. + tbb::mutex& cancel_mutex(); + std::function cancel_callback(); Print *m_print; ModelObject *m_model_object; @@ -534,7 +538,8 @@ protected: void set_done(PrintStep step) { m_state.set_done(step, m_mutex); throw_if_canceled(); } bool invalidate_step(PrintStep step); template - bool invalidate_multiple_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, m_mutex, m_cancel_callback); } + bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, m_mutex, m_cancel_callback); } + bool invalidate_steps(std::initializer_list il) { return m_state.invalidate_multiple(il.begin(), il.end(), m_mutex, m_cancel_callback); } bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); } // methods for handling regions diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index b7b33087f4..6527a72721 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -99,11 +99,9 @@ bool PrintObject::set_copies(const Points &points) // Invalidate and set copies. bool invalidated = false; if (copies != m_copies) { - invalidated = m_print->invalidate_step(psSkirt); - invalidated |= m_print->invalidate_step(psBrim); + invalidated = m_print->invalidate_steps({ psSkirt, psBrim, psGCodeExport }); if (copies.size() != m_copies.size()) invalidated |= m_print->invalidate_step(psWipeTower); - invalidated |= m_print->invalidate_step(psGCodeExport); m_copies = copies; } return invalidated; @@ -590,21 +588,16 @@ bool PrintObject::invalidate_step(PrintObjectStep step) // propagate to dependent steps if (step == posPerimeters) { invalidated |= this->invalidate_step(posPrepareInfill); - invalidated |= m_print->invalidate_step(psSkirt); - invalidated |= m_print->invalidate_step(psBrim); + invalidated |= m_print->invalidate_steps({ psSkirt, psBrim }); } else if (step == posPrepareInfill) { invalidated |= this->invalidate_step(posInfill); } else if (step == posInfill) { - invalidated |= m_print->invalidate_step(psSkirt); - invalidated |= m_print->invalidate_step(psBrim); + invalidated |= m_print->invalidate_steps({ psSkirt, psBrim }); } else if (step == posSlice) { - invalidated |= this->invalidate_step(posPerimeters); - invalidated |= this->invalidate_step(posSupportMaterial); + invalidated |= this->invalidate_steps({ posPerimeters, posSupportMaterial }); invalidated |= m_print->invalidate_step(psWipeTower); - } else if (step == posSupportMaterial) { - invalidated |= m_print->invalidate_step(psSkirt); - invalidated |= m_print->invalidate_step(psBrim); - } + } else if (step == posSupportMaterial) + invalidated |= m_print->invalidate_steps({ psSkirt, psBrim }); // Wipe tower depends on the ordering of extruders, which in turn depends on everything. // It also decides about what the wipe_into_infill / wipe_into_object features will do, @@ -613,11 +606,6 @@ bool PrintObject::invalidate_step(PrintObjectStep step) return invalidated; } -bool PrintObject::invalidate_all_steps() -{ - return m_state.invalidate_all(m_print->m_mutex, m_print->m_cancel_callback); -} - bool PrintObject::has_support_material() const { return m_config.support_material @@ -2254,4 +2242,15 @@ void PrintObject::adjust_layer_height_profile(coordf_t z, coordf_t layer_thickne layer_height_profile_valid = false; } +tbb::mutex& PrintObject::cancel_mutex() +{ + return m_print->m_mutex; +} + +std::function PrintObject::cancel_callback() +{ + return m_print->m_cancel_callback; +} + + } // namespace Slic3r From da37094a09e40c72dfe44b4d7d78cb71a9bf1212 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 31 Oct 2018 20:02:07 +0100 Subject: [PATCH 07/12] Bugfix: Slice at the correct height. --- src/libslic3r/Print.cpp | 8 +++++--- src/libslic3r/Print.hpp | 16 +++++++++------- src/libslic3r/PrintObject.cpp | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 770d02a7c6..d6f0d9e0d0 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -686,9 +686,11 @@ static std::vector print_objects_from_model_object(const ModelOb trafo.copies.assign(1, Point()); for (ModelInstance *model_instance : model_object.instances) if (model_instance->is_printable()) { - const Vec3d &offst = model_instance->get_offset(); - trafo.trafo = model_instance->world_matrix(true); - trafo.copies.front() = Point::new_scale(offst(0), offst(1)); + trafo.trafo = model_instance->world_matrix(); + // Set the Z axis of the transformation. + trafo.copies.front() = Point::new_scale(trafo.trafo.data()[3], trafo.trafo.data()[7]); + trafo.trafo.data()[3] = 0; + trafo.trafo.data()[7] = 0; auto it = trafos.find(trafo); if (it == trafos.end()) trafos.emplace(trafo); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index d2dc81755f..3c2a87c743 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -135,14 +135,16 @@ public: bool invalidated = false; for (size_t i = 0; i < COUNT; ++ i) if (m_state[i].load(std::memory_order_relaxed) != INVALID) { - if (! invalidated) { - mtx.unlock(); - cancel(); - mtx.lock(); - invalidated = true; - } - m_state[i].store(INVALID, std::memory_order_relaxed); + invalidated = true; + break; } + if (invalidated) { + mtx.unlock(); + cancel(); + for (size_t i = 0; i < COUNT; ++ i) + m_state[i].store(INVALID, std::memory_order_relaxed); + mtx.lock(); + } return invalidated; } diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 6527a72721..8f91467667 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1604,8 +1604,8 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, mesh.merge(v->mesh); if (mesh.stl.stats.number_of_facets > 0) { mesh.transform(m_trafo.cast()); - // align mesh to Z = 0 (it should be already aligned actually) and apply XY shift - mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), - float(this->model_object()->bounding_box().min(2))); + // apply XY shift + mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); // perform actual slicing TriangleMeshSlicer mslicer; const Print *print = this->print(); From 00222226ed0d7e8b56a7550c14ebbd611d1ab592 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 1 Nov 2018 08:46:44 +0100 Subject: [PATCH 08/12] Mirror component of transformations set as default --- src/libslic3r/Format/3mf.cpp | 4 -- src/libslic3r/Format/AMF.cpp | 26 ------------ src/libslic3r/Geometry.cpp | 61 ++++------------------------ src/libslic3r/Geometry.hpp | 36 +--------------- src/libslic3r/Model.cpp | 14 ------- src/libslic3r/Model.hpp | 29 +------------ src/libslic3r/Technologies.hpp | 2 - src/slic3r/GUI/3DScene.cpp | 12 ------ src/slic3r/GUI/3DScene.hpp | 10 +---- src/slic3r/GUI/GLCanvas3D.cpp | 10 ----- src/slic3r/GUI/GLCanvas3D.hpp | 6 --- src/slic3r/GUI/GLCanvas3DManager.cpp | 2 - src/slic3r/GUI/GLCanvas3DManager.hpp | 2 - src/slic3r/GUI/GLGizmo.cpp | 5 --- src/slic3r/GUI/Plater.cpp | 37 ----------------- 15 files changed, 10 insertions(+), 246 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index bd67a2fce1..5dd6f8a8e1 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1333,7 +1333,6 @@ namespace Slic3r { Vec3d offset = transform.matrix().block(0, 3, 3, 1); Eigen::Matrix m3x3 = transform.matrix().block(0, 0, 3, 3); -#if ENABLE_MIRROR // mirror // it is impossible to reconstruct the original mirroring factors from a matrix, // we can only detect if the matrix contains a left handed reference system @@ -1347,7 +1346,6 @@ namespace Slic3r { } // scale -#endif // ENABLE_MIRROR Vec3d scale(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm()); // invalid scale value, return @@ -1364,9 +1362,7 @@ namespace Slic3r { instance.set_offset(offset); instance.set_scaling_factor(scale); instance.set_rotation(rotation); -#if ENABLE_MIRROR instance.set_mirror(mirror); -#endif // ENABLE_MIRROR } bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 615dff0017..36964d8691 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -32,9 +32,7 @@ // 2 : Added z component of offset // Added x and y components of rotation // Added x, y and z components of scale -#if ENABLE_MIRROR // Added x, y and z components of mirror -#endif // ENABLE_MIRROR const unsigned int VERSION_AMF = 2; const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version"; @@ -132,24 +130,18 @@ struct AMFParserContext NODE_TYPE_SCALEX, // amf/constellation/instance/scalex NODE_TYPE_SCALEY, // amf/constellation/instance/scaley NODE_TYPE_SCALEZ, // amf/constellation/instance/scalez -#if ENABLE_MIRROR NODE_TYPE_MIRRORX, // amf/constellation/instance/mirrorx NODE_TYPE_MIRRORY, // amf/constellation/instance/mirrory NODE_TYPE_MIRRORZ, // amf/constellation/instance/mirrorz -#endif // ENABLE_MIRROR NODE_TYPE_METADATA, // anywhere under amf/*/metadata }; struct Instance { -#if ENABLE_MIRROR Instance() : deltax_set(false), deltay_set(false), deltaz_set(false) , rx_set(false), ry_set(false), rz_set(false) , scalex_set(false), scaley_set(false), scalez_set(false) , mirrorx_set(false), mirrory_set(false), mirrorz_set(false) {} -#else - Instance() : deltax_set(false), deltay_set(false), deltaz_set(false), rx_set(false), ry_set(false), rz_set(false), scalex_set(false), scaley_set(false), scalez_set(false) {} -#endif // ENABLE_MIRROR // Shift in the X axis. float deltax; bool deltax_set; @@ -175,7 +167,6 @@ struct AMFParserContext bool scaley_set; float scalez; bool scalez_set; -#if ENABLE_MIRROR // Mirroring factors float mirrorx; bool mirrorx_set; @@ -183,7 +174,6 @@ struct AMFParserContext bool mirrory_set; float mirrorz; bool mirrorz_set; -#endif // ENABLE_MIRROR }; struct Object { @@ -314,14 +304,12 @@ void AMFParserContext::startElement(const char *name, const char **atts) node_type_new = NODE_TYPE_SCALEZ; else if (strcmp(name, "scale") == 0) node_type_new = NODE_TYPE_SCALE; -#if ENABLE_MIRROR else if (strcmp(name, "mirrorx") == 0) node_type_new = NODE_TYPE_MIRRORX; else if (strcmp(name, "mirrory") == 0) node_type_new = NODE_TYPE_MIRRORY; else if (strcmp(name, "mirrorz") == 0) node_type_new = NODE_TYPE_MIRRORZ; -#endif // ENABLE_MIRROR } break; case 4: @@ -387,14 +375,10 @@ void AMFParserContext::characters(const XML_Char *s, int len) m_path.back() == NODE_TYPE_SCALEX || m_path.back() == NODE_TYPE_SCALEY || m_path.back() == NODE_TYPE_SCALEZ || -#if ENABLE_MIRROR m_path.back() == NODE_TYPE_SCALE || m_path.back() == NODE_TYPE_MIRRORX || m_path.back() == NODE_TYPE_MIRRORY || m_path.back() == NODE_TYPE_MIRRORZ) -#else - m_path.back() == NODE_TYPE_SCALE) -#endif // ENABLE_MIRROR m_value[0].append(s, len); break; case 6: @@ -486,7 +470,6 @@ void AMFParserContext::endElement(const char * /* name */) m_instance->scalez_set = true; m_value[0].clear(); break; -#if ENABLE_MIRROR case NODE_TYPE_MIRRORX: assert(m_instance); m_instance->mirrorx = float(atof(m_value[0].c_str())); @@ -505,7 +488,6 @@ void AMFParserContext::endElement(const char * /* name */) m_instance->mirrorz_set = true; m_value[0].clear(); break; -#endif // ENABLE_MIRROR // Object vertices: case NODE_TYPE_VERTEX: @@ -665,9 +647,7 @@ void AMFParserContext::endDocument() mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0)); mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0)); mi->set_scaling_factor(Vec3d(instance.scalex_set ? (double)instance.scalex : 1.0, instance.scaley_set ? (double)instance.scaley : 1.0, instance.scalez_set ? (double)instance.scalez : 1.0)); -#if ENABLE_MIRROR mi->set_mirror(Vec3d(instance.mirrorx_set ? (double)instance.mirrorx : 1.0, instance.mirrory_set ? (double)instance.mirrory : 1.0, instance.mirrorz_set ? (double)instance.mirrorz : 1.0)); -#endif // ENABLE_MIRROR } } } @@ -987,11 +967,9 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c " %lf\n" " %lf\n" " %lf\n" -#if ENABLE_MIRROR " %lf\n" " %lf\n" " %lf\n" -#endif // ENABLE_MIRROR " \n", object_id, instance->get_offset(X), @@ -1002,14 +980,10 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c instance->get_rotation(Z), instance->get_scaling_factor(X), instance->get_scaling_factor(Y), -#if ENABLE_MIRROR instance->get_scaling_factor(Z), instance->get_mirror(X), instance->get_mirror(Y), instance->get_mirror(Z)); -#else - instance->get_scaling_factor(Z)); -#endif // ENABLE_MIRROR //FIXME missing instance->scaling_factor instances.append(buf); diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 0cfd3f115e..83ebb3b32e 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1161,11 +1161,7 @@ MedialAxis::retrieve_endpoint(const VD::cell_type* cell) const } } -#if ENABLE_MIRROR void assemble_transform(Transform3d& transform, const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale, const Vec3d& mirror) -#else -void assemble_transform(Transform3d& transform, const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale) -#endif // ENABLE_MIRROR { transform = Transform3d::Identity(); transform.translate(translation); @@ -1173,23 +1169,13 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation, const transform.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY())); transform.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX())); transform.scale(scale); -#if ENABLE_MIRROR transform.scale(mirror); -#endif // ENABLE_MIRROR } -#if ENABLE_MIRROR Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale, const Vec3d& mirror) -#else -Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale) -#endif // ENABLE_MIRROR { Transform3d transform; -#if ENABLE_MIRROR assemble_transform(transform, translation, rotation, scale, mirror); -#else - assemble_transform(transform, translation, rotation, scale); -#endif // ENABLE_MIRROR return transform; } @@ -1232,13 +1218,10 @@ Transformation::Flags::Flags() : dont_translate(true) , dont_rotate(true) , dont_scale(true) -#if ENABLE_MIRROR , dont_mirror(true) -#endif // ENABLE_MIRROR { } -#if ENABLE_MIRROR bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const { return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror); @@ -1251,27 +1234,12 @@ void Transformation::Flags::set(bool dont_translate, bool dont_rotate, bool dont this->dont_scale = dont_scale; this->dont_mirror = dont_mirror; } -#else -bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale) const -{ - return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale); -} - -void Transformation::Flags::set(bool dont_translate, bool dont_rotate, bool dont_scale) -{ - this->dont_translate = dont_translate; - this->dont_rotate = dont_rotate; - this->dont_scale = dont_scale; -} -#endif // ENABLE_MIRROR Transformation::Transformation() : m_offset(Vec3d::Zero()) , m_rotation(Vec3d::Zero()) , m_scaling_factor(Vec3d::Ones()) -#if ENABLE_MIRROR , m_mirror(Vec3d::Ones()) -#endif // ENABLE_MIRROR , m_matrix(Transform3d::Identity()) , m_dirty(false) { @@ -1349,33 +1317,18 @@ void Transformation::set_mirror(Axis axis, double mirror) } } -#if ENABLE_MIRROR -const Transform3d& Transformation::world_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const -#else -const Transform3d& Transformation::world_matrix(bool dont_translate, bool dont_rotate, bool dont_scale) const -#endif // ENABLE_MIRROR +const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const { -#if ENABLE_MIRROR if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) -#else - if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale)) -#endif // ENABLE_MIRROR { - Vec3d translation = dont_translate ? Vec3d::Zero() : m_offset; - Vec3d rotation = dont_rotate ? Vec3d::Zero() : m_rotation; - Vec3d scale = dont_scale ? Vec3d::Ones() : m_scaling_factor; -#if ENABLE_MIRROR - Vec3d mirror = dont_mirror ? Vec3d::Ones() : m_mirror; - m_matrix = Geometry::assemble_transform(translation, rotation, scale, mirror); -#else - m_matrix = Geometry::assemble_transform(translation, rotation, scale); -#endif // ENABLE_MIRROR + m_matrix = Geometry::assemble_transform( + dont_translate ? Vec3d::Zero() : m_offset, + dont_rotate ? Vec3d::Zero() : m_rotation, + dont_scale ? Vec3d::Ones() : m_scaling_factor, + dont_mirror ? Vec3d::Ones() : m_mirror + ); -#if ENABLE_MIRROR m_flags.set(dont_translate, dont_rotate, dont_scale, dont_mirror); -#else - m_flags.set(dont_translate, dont_rotate, dont_scale); -#endif // ENABLE_MIRROR m_dirty = false; } diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 47fdec55a0..fd3560b7be 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -172,7 +172,6 @@ class MedialAxis { }; // Sets the given transform by assembling the given transformations in the following order: -#if ENABLE_MIRROR // 1) mirror // 2) scale // 3) rotate X @@ -180,17 +179,8 @@ class MedialAxis { // 5) rotate Z // 6) translate void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); -#else -// 1) scale -// 2) rotate X -// 3) rotate Y -// 4) rotate Z -// 5) translate -void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones()); -#endif // ENABLE_MIRROR // Returns the transform obtained by assembling the given transformations in the following order: -#if ENABLE_MIRROR // 1) mirror // 2) scale // 3) rotate X @@ -198,14 +188,6 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d // 5) rotate Z // 6) translate Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); -#else -// 1) scale -// 2) rotate X -// 3) rotate Y -// 4) rotate Z -// 5) translate -Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones()); -#endif // ENABLE_MIRROR // Returns the euler angles extracted from the given rotation matrix // Warning -> The matrix should not contain any scale or shear !!! @@ -223,27 +205,18 @@ class Transformation bool dont_translate; bool dont_rotate; bool dont_scale; -#if ENABLE_MIRROR bool dont_mirror; -#endif // ENABLE_MIRROR Flags(); -#if ENABLE_MIRROR bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const; void set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror); -#else - bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale) const; - void set(bool dont_translate, bool dont_rotate, bool dont_scale); -#endif // ENABLE_MIRROR }; Vec3d m_offset; // In unscaled coordinates Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point Vec3d m_scaling_factor; // Scaling factors along the three axes -#if ENABLE_MIRROR Vec3d m_mirror; // Mirroring along the three axes -#endif // ENABLE_MIRROR mutable Transform3d m_matrix; mutable Flags m_flags; @@ -267,7 +240,6 @@ public: Vec3d get_scaling_factor() const { return m_scaling_factor; } double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); } -#if ENABLE_MIRROR void set_scaling_factor(const Vec3d& scaling_factor); void set_scaling_factor(Axis axis, double scaling_factor); @@ -277,13 +249,7 @@ public: void set_mirror(const Vec3d& mirror); void set_mirror(Axis axis, double mirror); - const Transform3d& world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const; -#else - void set_scaling_factor(const Vec3d& scaling_factor) { m_scaling_factor = scaling_factor; } - void set_scaling_factor(Axis axis, double scaling_factor) { m_scaling_factor(axis) = scaling_factor; } - - const Transform3d& world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false) const; -#endif // ENABLE_MIRROR + const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const; }; #endif // ENABLE_MODELVOLUME_TRANSFORM diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 360a215cd5..9aad49397f 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1146,7 +1146,6 @@ void ModelInstance::set_rotation(Axis axis, double rotation) m_rotation(axis) = rotation; } -#if ENABLE_MIRROR void ModelInstance::set_scaling_factor(const Vec3d& scaling_factor) { set_scaling_factor(X, scaling_factor(0)); @@ -1176,7 +1175,6 @@ void ModelInstance::set_mirror(Axis axis, double mirror) m_mirror(axis) = mirror; } -#endif // ENABLE_MIRROR #endif // !ENABLE_MODELVOLUME_TRANSFORM void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const @@ -1188,11 +1186,7 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes { // Rotate around mesh origin. TriangleMesh copy(*mesh); -#if ENABLE_MIRROR copy.transform(world_matrix(true, false, true, true).cast()); -#else - copy.transform(world_matrix(true, false, true).cast()); -#endif // ENABLE_MIRROR BoundingBoxf3 bbox = copy.bounding_box(); if (!empty(bbox)) { @@ -1253,21 +1247,13 @@ void ModelInstance::transform_polygon(Polygon* polygon) const } #if !ENABLE_MODELVOLUME_TRANSFORM -#if ENABLE_MIRROR Transform3d ModelInstance::world_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const -#else -Transform3d ModelInstance::world_matrix(bool dont_translate, bool dont_rotate, bool dont_scale) const -#endif // ENABLE_MIRROR { Vec3d translation = dont_translate ? Vec3d::Zero() : m_offset; Vec3d rotation = dont_rotate ? Vec3d::Zero() : m_rotation; Vec3d scale = dont_scale ? Vec3d::Ones() : m_scaling_factor; -#if ENABLE_MIRROR Vec3d mirror = dont_mirror ? Vec3d::Ones() : m_mirror; return Geometry::assemble_transform(translation, rotation, scale, mirror); -#else - return Geometry::assemble_transform(translation, rotation, scale); -#endif // ENABLE_MIRROR } #endif // !ENABLE_MODELVOLUME_TRANSFORM diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 9739956a8f..df7798a50b 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -283,13 +283,11 @@ public: void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); } void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); } -#if ENABLE_MIRROR const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } -#endif // ENABLE_MIRROR #endif // ENABLE_MODELVOLUME_TRANSFORM private: @@ -347,9 +345,7 @@ private: Vec3d m_offset; // in unscaled coordinates Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point Vec3d m_scaling_factor; // Scaling factors along the three axes -#if ENABLE_MIRROR Vec3d m_mirror; // Mirroring along the three axes -#endif // ENABLE_MIRROR #endif // ENABLE_MODELVOLUME_TRANSFORM public: @@ -380,13 +376,11 @@ public: void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); } void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); } -#if ENABLE_MIRROR const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } -#endif // ENABLE_MIRROR #else const Vec3d& get_offset() const { return m_offset; } double get_offset(Axis axis) const { return m_offset(axis); } @@ -403,21 +397,14 @@ public: Vec3d get_scaling_factor() const { return m_scaling_factor; } double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); } -#if ENABLE_MIRROR void set_scaling_factor(const Vec3d& scaling_factor); void set_scaling_factor(Axis axis, double scaling_factor); -#else - void set_scaling_factor(const Vec3d& scaling_factor) { m_scaling_factor = scaling_factor; } - void set_scaling_factor(Axis axis, double scaling_factor) { m_scaling_factor(axis) = scaling_factor; } -#endif // ENABLE_MIRROR -#if ENABLE_MIRROR const Vec3d& get_mirror() const { return m_mirror; } double get_mirror(Axis axis) const { return m_mirror(axis); } void set_mirror(const Vec3d& mirror); void set_mirror(Axis axis, double mirror); -#endif // ENABLE_MIRROR #endif // ENABLE_MODELVOLUME_TRANSFORM // To be called on an external mesh @@ -432,17 +419,9 @@ public: void transform_polygon(Polygon* polygon) const; #if ENABLE_MODELVOLUME_TRANSFORM -#if ENABLE_MIRROR - const Transform3d& world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.world_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } + const Transform3d& world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } #else - const Transform3d& world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false) const { return m_transformation.world_matrix(dont_translate, dont_rotate, dont_scale); } -#endif // ENABLE_MIRROR -#else -#if ENABLE_MIRROR Transform3d world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const; -#else - Transform3d world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false) const; -#endif // ENABLE_MIRROR #endif // ENABLE_MODELVOLUME_TRANSFORM bool is_printable() const { return print_volume_state == PVS_Inside; } @@ -456,15 +435,9 @@ private: ModelInstance(ModelObject *object, const ModelInstance &other) : m_transformation(other.m_transformation), object(object), print_volume_state(PVS_Inside) {} #else -#if ENABLE_MIRROR ModelInstance(ModelObject *object) : m_offset(Vec3d::Zero()), m_rotation(Vec3d::Zero()), m_scaling_factor(Vec3d::Ones()), m_mirror(Vec3d::Ones()), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object, const ModelInstance &other) : m_offset(other.m_offset), m_rotation(other.m_rotation), m_scaling_factor(other.m_scaling_factor), m_mirror(other.m_mirror), object(object), print_volume_state(PVS_Inside) {} -#else - ModelInstance(ModelObject *object) : m_rotation(Vec3d::Zero()), m_scaling_factor(Vec3d::Ones()), m_offset(Vec3d::Zero()), object(object), print_volume_state(PVS_Inside) {} - ModelInstance(ModelObject *object, const ModelInstance &other) : - m_rotation(other.m_rotation), m_scaling_factor(other.m_scaling_factor), m_offset(other.m_offset), object(object), print_volume_state(PVS_Inside) {} -#endif // ENABLE_MIRROR #endif // ENABLE_MODELVOLUME_TRANSFORM explicit ModelInstance(ModelInstance &rhs) = delete; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index fe3b19eb08..a844d5f4b6 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -20,8 +20,6 @@ // New selections #define ENABLE_EXTENDED_SELECTION (1 && ENABLE_1_42_0) #define DISABLE_INSTANCES_SYNCH (1 && ENABLE_EXTENDED_SELECTION) -// Add mirror components along the three axes in ModelInstance and GLVolume -#define ENABLE_MIRROR (1 && ENABLE_1_42_0) // Modified camera target behavior #define ENABLE_MODIFIED_CAMERA_TARGET (1 && ENABLE_1_42_0) // Add Geometry::Transformation class and use it into ModelInstance, ModelVolume and GLVolume diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a85a27e1d7..924b969e06 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -201,9 +201,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) : m_offset(Vec3d::Zero()) , m_rotation(Vec3d::Zero()) , m_scaling_factor(Vec3d::Ones()) -#if ENABLE_MIRROR , m_mirror(Vec3d::Ones()) -#endif // ENABLE_MIRROR , m_world_matrix(Transform3f::Identity()) , m_world_matrix_dirty(true) , m_transformed_bounding_box_dirty(true) @@ -332,7 +330,6 @@ void GLVolume::set_scaling_factor(const Vec3d& scaling_factor) } } -#if ENABLE_MIRROR const Vec3d& GLVolume::get_mirror() const { return m_mirror; @@ -364,7 +361,6 @@ void GLVolume::set_mirror(Axis axis, double mirror) m_transformed_convex_hull_bounding_box_dirty = true; } } -#endif // ENABLE_MIRROR #endif // !ENABLE_MODELVOLUME_TRANSFORM void GLVolume::set_convex_hull(const TriangleMesh& convex_hull) @@ -397,11 +393,7 @@ const Transform3f& GLVolume::world_matrix() const { if (m_world_matrix_dirty) { -#if ENABLE_MIRROR m_world_matrix = Geometry::assemble_transform(m_offset, m_rotation, m_scaling_factor, m_mirror).cast(); -#else - m_world_matrix = Geometry::assemble_transform(m_offset, m_rotation, m_scaling_factor).cast(); -#endif // ENABLE_MIRROR m_world_matrix_dirty = false; } return m_world_matrix; @@ -816,9 +808,7 @@ std::vector GLVolumeCollection::load_object( v.set_offset(instance->get_offset()); v.set_rotation(instance->get_rotation()); v.set_scaling_factor(instance->get_scaling_factor()); -#if ENABLE_MIRROR v.set_mirror(instance->get_mirror()); -#endif // ENABLE_MIRROR #endif // ENABLE_MODELVOLUME_TRANSFORM } } @@ -2167,14 +2157,12 @@ int _3DScene::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) return s_canvas_mgr.get_in_object_volume_id(canvas, scene_vol_idx); } -#if ENABLE_MIRROR #if ENABLE_EXTENDED_SELECTION void _3DScene::mirror_selection(wxGLCanvas* canvas, Axis axis) { s_canvas_mgr.mirror_selection(canvas, axis); } #endif // ENABLE_EXTENDED_SELECTION -#endif // ENABLE_MIRROR void _3DScene::reload_scene(wxGLCanvas* canvas, bool force) { diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 8c24279152..35638b2efa 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -263,10 +263,8 @@ private: Vec3d m_rotation; // Scale factor along the three axes of the volume to be rendered. Vec3d m_scaling_factor; -#if ENABLE_MIRROR // Mirroring along the three axes of the volume to be rendered. Vec3d m_mirror; -#endif // ENABLE_MIRROR // World matrix of the volume to be rendered. mutable Transform3f m_world_matrix; // Whether or not is needed to recalculate the world matrix. @@ -358,13 +356,11 @@ public: void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); } void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); } -#if ENABLE_MIRROR const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); } -#endif // ENABLE_MIRROR #else const Vec3d& get_rotation() const; void set_rotation(const Vec3d& rotation); @@ -374,12 +370,10 @@ public: #endif // ENABLE_EXTENDED_SELECTION void set_scaling_factor(const Vec3d& scaling_factor); -#if ENABLE_MIRROR const Vec3d& get_mirror() const; double get_mirror(Axis axis) const; void set_mirror(const Vec3d& mirror); void set_mirror(Axis axis, double mirror); -#endif // ENABLE_MIRROR const Vec3d& get_offset() const; void set_offset(const Vec3d& offset); @@ -397,7 +391,7 @@ public: int instance_idx() const { return this->composite_id % 1000; } #if ENABLE_MODELVOLUME_TRANSFORM - const Transform3d& world_matrix() const { return m_transformation.world_matrix(); } + const Transform3d& world_matrix() const { return m_transformation.get_matrix(); } #else const Transform3f& world_matrix() const; #endif // ENABLE_MODELVOLUME_TRANSFORM @@ -634,11 +628,9 @@ public: static int get_first_volume_id(wxGLCanvas* canvas, int obj_idx); static int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx); -#if ENABLE_MIRROR #if ENABLE_EXTENDED_SELECTION static void mirror_selection(wxGLCanvas* canvas, Axis axis); #endif // ENABLE_EXTENDED_SELECTION -#endif // ENABLE_MIRROR static void reload_scene(wxGLCanvas* canvas, bool force); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index afa2ee9911..5a03be0865 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1463,7 +1463,6 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) m_bounding_box_dirty = true; } -#if ENABLE_MIRROR void GLCanvas3D::Selection::mirror(Axis axis) { if (!m_valid) @@ -1482,7 +1481,6 @@ void GLCanvas3D::Selection::mirror(Axis axis) m_bounding_box_dirty = true; } -#endif // ENABLE_MIRROR void GLCanvas3D::Selection::translate(unsigned int object_idx, const Vec3d& displacement) { @@ -1897,9 +1895,7 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() int instance_idx = volume->instance_idx(); const Vec3d& rotation = volume->get_rotation(); const Vec3d& scaling_factor = volume->get_scaling_factor(); -#if ENABLE_MIRROR const Vec3d& mirror = volume->get_mirror(); -#endif // ENABLE_MIRROR // Process unselected instances. for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) @@ -1916,9 +1912,7 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() v->set_rotation(rotation); v->set_scaling_factor(scaling_factor); -#if ENABLE_MIRROR v->set_mirror(mirror); -#endif // ENABLE_MIRROR done.insert(j); } @@ -3608,7 +3602,6 @@ int GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const return ((0 <= scene_vol_idx) && (scene_vol_idx < (int)m_volumes.volumes.size())) ? m_volumes.volumes[scene_vol_idx]->volume_idx() : -1; } -#if ENABLE_MIRROR #if ENABLE_EXTENDED_SELECTION void GLCanvas3D::mirror_selection(Axis axis) { @@ -3617,7 +3610,6 @@ void GLCanvas3D::mirror_selection(Axis axis) wxGetApp().obj_manipul()->update_settings_value(m_selection); } #endif // ENABLE_EXTENDED_SELECTION -#endif // ENABLE_MIRROR void GLCanvas3D::reload_scene(bool force) { @@ -6868,7 +6860,6 @@ void GLCanvas3D::_on_flatten() _on_rotate(); } -#if ENABLE_MIRROR void GLCanvas3D::_on_mirror() { if (m_model == nullptr) @@ -6902,7 +6893,6 @@ void GLCanvas3D::_on_mirror() post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } -#endif // ENABLE_MIRROR #else void GLCanvas3D::_on_move(const std::vector& volume_idxs) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 4d21858258..779dce98b1 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -504,9 +504,7 @@ public: void translate(const Vec3d& displacement); void rotate(const Vec3d& rotation); void scale(const Vec3d& scale); -#if ENABLE_MIRROR void mirror(Axis axis); -#endif // ENABLE_MIRROR void translate(unsigned int object_idx, const Vec3d& displacement); void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement); @@ -855,11 +853,9 @@ public: int get_first_volume_id(int obj_idx) const; int get_in_object_volume_id(int scene_vol_idx) const; -#if ENABLE_MIRROR #if ENABLE_EXTENDED_SELECTION void mirror_selection(Axis axis); #endif // ENABLE_EXTENDED_SELECTION -#endif // ENABLE_MIRROR void reload_scene(bool force); @@ -986,9 +982,7 @@ private: void _on_rotate(); void _on_scale(); void _on_flatten(); -#if ENABLE_MIRROR void _on_mirror(); -#endif // ENABLE_MIRROR #else void _on_move(const std::vector& volume_idxs); #endif // ENABLE_EXTENDED_SELECTION diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 1d963e3b7b..9a673b703e 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -596,7 +596,6 @@ int GLCanvas3DManager::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol return (it != m_canvases.end()) ? it->second->get_in_object_volume_id(scene_vol_idx) : -1; } -#if ENABLE_MIRROR #if ENABLE_EXTENDED_SELECTION void GLCanvas3DManager::mirror_selection(wxGLCanvas* canvas, Axis axis) { @@ -605,7 +604,6 @@ void GLCanvas3DManager::mirror_selection(wxGLCanvas* canvas, Axis axis) it->second->mirror_selection(axis); } #endif // ENABLE_EXTENDED_SELECTION -#endif // ENABLE_MIRROR void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force) { diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 89cb09e7f0..66d5fb1cd3 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -163,11 +163,9 @@ public: int get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const; int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const; -#if ENABLE_MIRROR #if ENABLE_EXTENDED_SELECTION void mirror_selection(wxGLCanvas* canvas, Axis axis); #endif // ENABLE_EXTENDED_SELECTION -#endif // ENABLE_MIRROR void reload_scene(wxGLCanvas* canvas, bool force); diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 62fba6c5a7..17e42f5f75 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -935,13 +935,8 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const // gets angles from first selected volume angles = v->get_rotation(); -#if ENABLE_MIRROR // consider rotation+mirror only components of the transform for offsets offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_mirror()); -#else - // set rotation-only component of transform - offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles); -#endif // ENABLE_MIRROR } else box = selection.get_bounding_box(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 4896d5f2f9..1c21a27ca4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -932,9 +932,7 @@ private: bool layers_height_allowed() const; bool can_delete_all() const; bool can_arrange() const; -#if ENABLE_MIRROR bool can_mirror() const; -#endif // ENABLE_MIRROR #endif // ENABLE_EXTENDED_SELECTION }; @@ -1617,38 +1615,9 @@ void Plater::priv::rotate() void Plater::priv::mirror(Axis axis) { -#if ENABLE_MIRROR #if ENABLE_EXTENDED_SELECTION _3DScene::mirror_selection(canvas3D, axis); #endif // ENABLE_EXTENDED_SELECTION -#else -#if ENABLE_EXTENDED_SELECTION - int obj_idx = get_selected_object_idx(); - if (obj_idx == -1) - return; - - ModelObject* model_object = model.objects[obj_idx]; - ModelInstance* model_instance = model_object->instances.front(); -#else - const auto obj_idx = selected_object(); - if (! obj_idx) { return; } - - auto *model_object = model.objects[*obj_idx]; - auto *model_instance = model_object->instances[0]; -#endif // ENABLE_EXTENDED_SELECTION - - // XXX: ? - // # apply Z rotation before mirroring - // if ($model_instance->rotation != 0) { - // $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, 1)); - // $_->set_rotation(0) for @{ $model_object->instances }; - // } - - model_object->mirror(axis); - - selection_changed(); - update(); -#endif // ENABLE_MIRROR } #if !ENABLE_EXTENDED_SELECTION @@ -2109,7 +2078,6 @@ bool Plater::priv::init_object_menu() object_menu.AppendSeparator(); -#if ENABLE_MIRROR wxMenu* mirror_menu = new wxMenu(); if (mirror_menu == nullptr) return false; @@ -2122,7 +2090,6 @@ bool Plater::priv::init_object_menu() [this](wxCommandEvent&) { mirror(Z); }, "bullet_blue.png", &object_menu); wxMenuItem* item_mirror = append_submenu(&object_menu, mirror_menu, wxID_ANY, _(L("Mirror")), _(L("Mirror the selected object"))); -#endif // ENABLE_MIRROR wxMenu* split_menu = new wxMenu(); if (split_menu == nullptr) @@ -2139,9 +2106,7 @@ bool Plater::priv::init_object_menu() // ui updates needs to be binded to the parent panel if (q != nullptr) { -#if ENABLE_MIRROR q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_mirror()); }, item_mirror->GetId()); -#endif // ENABLE_MIRROR q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete_object()); }, item_delete->GetId()); q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_increase_instances()); }, item_increase->GetId()); q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_decrease_instances()); }, item_decrease->GetId()); @@ -2208,12 +2173,10 @@ bool Plater::priv::can_arrange() const return !model.objects.empty(); } -#if ENABLE_MIRROR bool Plater::priv::can_mirror() const { return get_selection().is_from_single_instance(); } -#endif // ENABLE_MIRROR #endif // ENABLE_EXTENDED_SELECTION // Plater / Public From 0d282896d002d6e320d8467b8f7e03b3ceadfb40 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 1 Nov 2018 08:50:54 +0100 Subject: [PATCH 09/12] Removed obsolete references to tech ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM --- src/slic3r/GUI/GLGizmo.cpp | 12 ------------ src/slic3r/GUI/GLGizmo.hpp | 6 ------ 2 files changed, 18 deletions(-) diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 17e42f5f75..90c2e0bcef 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1981,13 +1981,7 @@ bool GLGizmoSlaSupports::is_mesh_update_necessary() const if (m_state != On || !m_model_object || m_model_object->instances.empty()) return false; -#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM if ((m_model_object->instances.front()->world_matrix() * m_source_data.matrix.inverse() * Vec3d(1., 1., 1.) - Vec3d(1., 1., 1.)).norm() > 0.001 ) -#else - if (m_model_object->instances.front()->get_scaling_factor() != m_source_data.scaling_factor - || m_model_object->instances.front()->get_rotation() != m_source_data.rotation - || m_model_object->instances.front()->get_offset() != m_source_data.offset) -#endif // ENABLE_MODELINSTANCE_3D_ROTATION return true; // following should detect direct mesh changes (can be removed after the mesh is made completely immutable): @@ -2015,13 +2009,7 @@ void GLGizmoSlaSupports::update_mesh() F(i, 1) = 3*i+1; F(i, 2) = 3*i+2; } -#if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - m_source_data.scaling_factor = m_model_object->instances.front()->get_scaling_factor(); - m_source_data.rotation = m_model_object->instances.front()->get_rotation(); - m_source_data.offset = m_model_object->instances.front()->get_offset(); -#else m_source_data.matrix = m_model_object->instances.front()->world_matrix(); -#endif const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex(); m_source_data.mesh_first_point = Vec3d((double)first_vertex[0], (double)first_vertex[1], (double)first_vertex[2]); // we'll now reload Grabbers (selection might have changed): diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index 838c7b7871..cccdb2bb9b 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -497,13 +497,7 @@ private: Eigen::MatrixXi m_F; // facets indices struct SourceDataSummary { BoundingBoxf3 bounding_box; -#if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - Vec3d scaling_factor; - Vec3d rotation; - Vec3d offset; -#else Transform3d matrix; -#endif Vec3d mesh_first_point; }; From a15bf7cc25e682570ae9bee9b1fd1928f72e12aa Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 1 Nov 2018 10:06:55 +0100 Subject: [PATCH 10/12] New selection set as default --- src/libslic3r/Model.cpp | 11 - src/libslic3r/Technologies.hpp | 5 +- src/slic3r/GUI/3DScene.cpp | 112 --- src/slic3r/GUI/3DScene.hpp | 52 -- src/slic3r/GUI/GLCanvas3D.cpp | 856 +--------------------- src/slic3r/GUI/GLCanvas3D.hpp | 117 --- src/slic3r/GUI/GLCanvas3DManager.cpp | 56 -- src/slic3r/GUI/GLCanvas3DManager.hpp | 17 - src/slic3r/GUI/GLGizmo.cpp | 421 ----------- src/slic3r/GUI/GLGizmo.hpp | 118 --- src/slic3r/GUI/GLToolbar.cpp | 6 - src/slic3r/GUI/GLToolbar.hpp | 6 - src/slic3r/GUI/GUI_ObjectList.cpp | 15 - src/slic3r/GUI/GUI_ObjectManipulation.cpp | 2 - src/slic3r/GUI/GUI_ObjectManipulation.hpp | 5 - src/slic3r/GUI/Plater.cpp | 370 +--------- 16 files changed, 20 insertions(+), 2149 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 9aad49397f..89b476d755 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -693,23 +693,12 @@ void ModelObject::center_around_origin() if (v->is_model_part()) bb.merge(v->mesh.bounding_box()); -#if ENABLE_EXTENDED_SELECTION // Shift is the vector from the center of the bounding box to the origin Vec3d shift = -bb.center(); -#else - // Shift is the vector from the center of the bottom face of the bounding box to the origin - Vec3d shift = -bb.center(); - shift(2) = -bb.min(2); -#endif // ENABLE_EXTENDED_SELECTION this->translate(shift); this->origin_translation += shift; -#if !ENABLE_EXTENDED_SELECTION - // set z to zero, translation in z has already been done within the mesh - shift(2) = 0.0; -#endif // !ENABLE_EXTENDED_SELECTION - if (!this->instances.empty()) { for (ModelInstance *i : this->instances) { i->set_offset(i->get_offset() - shift); diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index a844d5f4b6..73d342f08c 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -17,9 +17,8 @@ #define ENABLE_GIZMOS_RESET (1 && ENABLE_1_42_0) // Uses a unique opengl context #define ENABLE_USE_UNIQUE_GLCONTEXT (1 && ENABLE_1_42_0) -// New selections -#define ENABLE_EXTENDED_SELECTION (1 && ENABLE_1_42_0) -#define DISABLE_INSTANCES_SYNCH (1 && ENABLE_EXTENDED_SELECTION) +// Disable synchronization of unselected instances +#define DISABLE_INSTANCES_SYNCH (1 && ENABLE_1_42_0) // Modified camera target behavior #define ENABLE_MODIFIED_CAMERA_TARGET (1 && ENABLE_1_42_0) // Add Geometry::Transformation class and use it into ModelInstance, ModelVolume and GLVolume diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 924b969e06..7745710e12 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -209,10 +209,6 @@ GLVolume::GLVolume(float r, float g, float b, float a) , m_transformed_convex_hull_bounding_box_dirty(true) , m_convex_hull(nullptr) , composite_id(-1) -#if !ENABLE_EXTENDED_SELECTION - , select_group_id(-1) - , drag_group_id(-1) -#endif // !ENABLE_EXTENDED_SELECTION , extruder_id(0) , selected(false) , is_active(true) @@ -270,14 +266,11 @@ const Vec3d& GLVolume::get_rotation() const void GLVolume::set_rotation(const Vec3d& rotation) { -#if ENABLE_EXTENDED_SELECTION static const double TWO_PI = 2.0 * (double)PI; -#endif // ENABLE_EXTENDED_SELECTION if (m_rotation != rotation) { m_rotation = rotation; -#if ENABLE_EXTENDED_SELECTION for (int i = 0; i < 3; ++i) { while (m_rotation(i) < 0.0) @@ -289,7 +282,6 @@ void GLVolume::set_rotation(const Vec3d& rotation) m_rotation(i) -= TWO_PI; } } -#endif // ENABLE_EXTENDED_SELECTION m_world_matrix_dirty = true; m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; @@ -312,12 +304,10 @@ void GLVolume::set_offset(const Vec3d& offset) } } -#if ENABLE_EXTENDED_SELECTION const Vec3d& GLVolume::get_scaling_factor() const { return m_scaling_factor; } -#endif // ENABLE_EXTENDED_SELECTION void GLVolume::set_scaling_factor(const Vec3d& scaling_factor) { @@ -368,26 +358,6 @@ void GLVolume::set_convex_hull(const TriangleMesh& convex_hull) m_convex_hull = &convex_hull; } -#if !ENABLE_EXTENDED_SELECTION -void GLVolume::set_select_group_id(const std::string& select_by) -{ - if (select_by == "object") - select_group_id = object_idx() * 1000000; - else if (select_by == "volume") - select_group_id = object_idx() * 1000000 + volume_idx() * 1000; - else if (select_by == "instance") - select_group_id = composite_id; -} - -void GLVolume::set_drag_group_id(const std::string& drag_by) -{ - if (drag_by == "object") - drag_group_id = object_idx() * 1000; - else if (drag_by == "instance") - drag_group_id = object_idx() * 1000 + instance_idx(); -} -#endif // !ENABLE_EXTENDED_SELECTION - #if !ENABLE_MODELVOLUME_TRANSFORM const Transform3f& GLVolume::world_matrix() const { @@ -722,23 +692,12 @@ void GLVolume::generate_layer_height_texture(const PrintObject *print_object, bo #define LAYER_HEIGHT_TEXTURE_WIDTH 1024 #define LAYER_HEIGHT_TEXTURE_HEIGHT 1024 -#if ENABLE_EXTENDED_SELECTION std::vector GLVolumeCollection::load_object( const ModelObject *model_object, int obj_idx, const std::vector &instance_idxs, const std::string &color_by, bool use_VBOs) -#else -std::vector GLVolumeCollection::load_object( - const ModelObject *model_object, - int obj_idx, - const std::vector &instance_idxs, - const std::string &color_by, - const std::string &select_by, - const std::string &drag_by, - bool use_VBOs) -#endif // ENABLE_EXTENDED_SELECTION { static float colors[4][4] = { { 1.0f, 1.0f, 0.0f, 1.f }, @@ -789,10 +748,6 @@ std::vector GLVolumeCollection::load_object( v.bounding_box = v.indexed_vertex_array.bounding_box(); v.indexed_vertex_array.finalize_geometry(use_VBOs); v.composite_id = obj_idx * 1000000 + volume_idx * 1000 + instance_idx; -#if !ENABLE_EXTENDED_SELECTION - v.set_select_group_id(select_by); - v.set_drag_group_id(drag_by); -#endif // !ENABLE_EXTENDED_SELECTION if (model_volume->is_model_part()) { v.set_convex_hull(model_volume->get_convex_hull()); @@ -884,10 +839,6 @@ int GLVolumeCollection::load_wipe_tower_preview( v.bounding_box = v.indexed_vertex_array.bounding_box(); v.indexed_vertex_array.finalize_geometry(use_VBOs); v.composite_id = obj_idx * 1000000; -#if !ENABLE_EXTENDED_SELECTION - v.select_group_id = obj_idx * 1000000; - v.drag_group_id = obj_idx * 1000; -#endif // !ENABLE_EXTENDED_SELECTION v.is_wipe_tower = true; v.shader_outside_printer_detection_enabled = ! size_unknown; return int(this->volumes.size() - 1); @@ -1083,26 +1034,6 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con } } -#if !ENABLE_EXTENDED_SELECTION -void GLVolumeCollection::set_select_by(const std::string& select_by) -{ - for (GLVolume *vol : this->volumes) - { - if (vol != nullptr) - vol->set_select_group_id(select_by); - } -} - -void GLVolumeCollection::set_drag_by(const std::string& drag_by) -{ - for (GLVolume *vol : this->volumes) - { - if (vol != nullptr) - vol->set_drag_group_id(drag_by); - } -} -#endif // !ENABLE_EXTENDED_SELECTION - std::vector GLVolumeCollection::get_current_print_zs(bool active_only) const { // Collect layer top positions of all volumes. @@ -1874,23 +1805,6 @@ void _3DScene::reset_volumes(wxGLCanvas* canvas) s_canvas_mgr.reset_volumes(canvas); } -#if !ENABLE_EXTENDED_SELECTION -void _3DScene::deselect_volumes(wxGLCanvas* canvas) -{ - s_canvas_mgr.deselect_volumes(canvas); -} - -void _3DScene::select_volume(wxGLCanvas* canvas, unsigned int id) -{ - s_canvas_mgr.select_volume(canvas, id); -} - -void _3DScene::update_volumes_selection(wxGLCanvas* canvas, const std::vector& selections) -{ - s_canvas_mgr.update_volumes_selection(canvas, selections); -} -#endif // !ENABLE_EXTENDED_SELECTION - int _3DScene::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) { return s_canvas_mgr.check_volumes_outside_state(canvas, config); @@ -1906,17 +1820,10 @@ bool _3DScene::move_volume_down(wxGLCanvas* canvas, unsigned int id) return s_canvas_mgr.move_volume_down(canvas, id); } -#if ENABLE_EXTENDED_SELECTION GUI::GLCanvas3D* _3DScene::get_canvas(wxGLCanvas* canvas) { return s_canvas_mgr.get_canvas(canvas); } -#else -void _3DScene::set_objects_selections(wxGLCanvas* canvas, const std::vector& selections) -{ - s_canvas_mgr.set_objects_selections(canvas, selections); -} -#endif // ENABLE_EXTENDED_SELECTION void _3DScene::set_config(wxGLCanvas* canvas, DynamicPrintConfig* config) { @@ -1963,23 +1870,6 @@ void _3DScene::set_color_by(wxGLCanvas* canvas, const std::string& value) s_canvas_mgr.set_color_by(canvas, value); } -#if !ENABLE_EXTENDED_SELECTION -void _3DScene::set_select_by(wxGLCanvas* canvas, const std::string& value) -{ - s_canvas_mgr.set_select_by(canvas, value); -} - -void _3DScene::set_drag_by(wxGLCanvas* canvas, const std::string& value) -{ - s_canvas_mgr.set_drag_by(canvas, value); -} - -std::string _3DScene::get_select_by(wxGLCanvas* canvas) -{ - return s_canvas_mgr.get_select_by(canvas); -} -#endif // !ENABLE_EXTENDED_SELECTION - bool _3DScene::is_layers_editing_enabled(wxGLCanvas* canvas) { return s_canvas_mgr.is_layers_editing_enabled(canvas); @@ -2157,12 +2047,10 @@ int _3DScene::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) return s_canvas_mgr.get_in_object_volume_id(canvas, scene_vol_idx); } -#if ENABLE_EXTENDED_SELECTION void _3DScene::mirror_selection(wxGLCanvas* canvas, Axis axis) { s_canvas_mgr.mirror_selection(canvas, axis); } -#endif // ENABLE_EXTENDED_SELECTION void _3DScene::reload_scene(wxGLCanvas* canvas, bool force) { diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 35638b2efa..d33f34b851 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -290,12 +290,6 @@ public: float render_color[4]; // An ID containing the object ID, volume ID and instance ID. int composite_id; -#if !ENABLE_EXTENDED_SELECTION - // An ID for group selection. It may be the same for all meshes of all object instances, or for just a single object instance. - int select_group_id; - // An ID for group dragging. It may be the same for all meshes of all object instances, or for just a single object instance. - int drag_group_id; -#endif // !ENABLE_EXTENDED_SELECTION // An ID containing the extruder ID (used to select color). int extruder_id; // Is this object selected? @@ -365,9 +359,7 @@ public: const Vec3d& get_rotation() const; void set_rotation(const Vec3d& rotation); -#if ENABLE_EXTENDED_SELECTION const Vec3d& get_scaling_factor() const; -#endif // ENABLE_EXTENDED_SELECTION void set_scaling_factor(const Vec3d& scaling_factor); const Vec3d& get_mirror() const; @@ -381,11 +373,6 @@ public: void set_convex_hull(const TriangleMesh& convex_hull); -#if !ENABLE_EXTENDED_SELECTION - void set_select_group_id(const std::string& select_by); - void set_drag_group_id(const std::string& drag_by); -#endif // !ENABLE_EXTENDED_SELECTION - int object_idx() const { return this->composite_id / 1000000; } int volume_idx() const { return (this->composite_id / 1000) % 1000; } int instance_idx() const { return this->composite_id % 1000; } @@ -450,9 +437,7 @@ public: #endif // ENABLE_MODELVOLUME_TRANSFORM }; -#if ENABLE_EXTENDED_SELECTION typedef std::vector GLVolumePtrs; -#endif // ENABLE_EXTENDED_SELECTION class GLVolumeCollection { @@ -461,32 +446,17 @@ class GLVolumeCollection float print_box_max[3]; public: -#if ENABLE_EXTENDED_SELECTION GLVolumePtrs volumes; -#else - std::vector volumes; -#endif // ENABLE_EXTENDED_SELECTION GLVolumeCollection() {}; ~GLVolumeCollection() { clear(); }; -#if ENABLE_EXTENDED_SELECTION std::vector load_object( const ModelObject *model_object, int obj_idx, const std::vector &instance_idxs, const std::string &color_by, bool use_VBOs); -#else - std::vector load_object( - const ModelObject *model_object, - int obj_idx, - const std::vector &instance_idxs, - const std::string &color_by, - const std::string &select_by, - const std::string &drag_by, - bool use_VBOs); -#endif // ENABLE_EXTENDED_SELECTION int load_wipe_tower_preview( int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width); @@ -520,11 +490,6 @@ public: void update_colors_by_extruder(const DynamicPrintConfig* config); -#if !ENABLE_EXTENDED_SELECTION - void set_select_by(const std::string& select_by); - void set_drag_by(const std::string& drag_by); -#endif // !ENABLE_EXTENDED_SELECTION - // Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection std::vector get_current_print_zs(bool active_only) const; @@ -552,20 +517,11 @@ public: static unsigned int get_volumes_count(wxGLCanvas* canvas); static void reset_volumes(wxGLCanvas* canvas); -#if !ENABLE_EXTENDED_SELECTION - static void deselect_volumes(wxGLCanvas* canvas); - static void select_volume(wxGLCanvas* canvas, unsigned int id); - static void update_volumes_selection(wxGLCanvas* canvas, const std::vector& selections); -#endif // !ENABLE_EXTENDED_SELECTION static int check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config); static bool move_volume_up(wxGLCanvas* canvas, unsigned int id); static bool move_volume_down(wxGLCanvas* canvas, unsigned int id); -#if ENABLE_EXTENDED_SELECTION static GUI::GLCanvas3D* get_canvas(wxGLCanvas* canvas); -#else - static void set_objects_selections(wxGLCanvas* canvas, const std::vector& selections); -#endif // ENABLE_EXTENDED_SELECTION static void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config); static void set_print(wxGLCanvas* canvas, Print* print); @@ -581,12 +537,6 @@ public: static void set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons); static void set_color_by(wxGLCanvas* canvas, const std::string& value); -#if !ENABLE_EXTENDED_SELECTION - static void set_select_by(wxGLCanvas* canvas, const std::string& value); - static void set_drag_by(wxGLCanvas* canvas, const std::string& value); - - static std::string get_select_by(wxGLCanvas* canvas); -#endif // !ENABLE_EXTENDED_SELECTION static bool is_layers_editing_enabled(wxGLCanvas* canvas); static bool is_layers_editing_allowed(wxGLCanvas* canvas); @@ -628,9 +578,7 @@ public: static int get_first_volume_id(wxGLCanvas* canvas, int obj_idx); static int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx); -#if ENABLE_EXTENDED_SELECTION static void mirror_selection(wxGLCanvas* canvas, Axis axis); -#endif // ENABLE_EXTENDED_SELECTION static void reload_scene(wxGLCanvas* canvas, bool force); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5a03be0865..5ea74fc174 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1093,14 +1093,7 @@ const Vec3d GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MAX) GLCanvas3D::Mouse::Drag::Drag() : start_position_2D(Invalid_2D_Point) , start_position_3D(Invalid_3D_Point) -#if !ENABLE_EXTENDED_SELECTION - , volume_center_offset(0, 0, 0) - , move_with_shift(false) -#endif // !ENABLE_EXTENDED_SELECTION , move_volume_idx(-1) -#if !ENABLE_EXTENDED_SELECTION - , gizmo_volume_idx(-1) -#endif // !ENABLE_EXTENDED_SELECTION { } @@ -1133,7 +1126,6 @@ bool GLCanvas3D::Mouse::is_start_position_3D_defined() const return (drag.start_position_3D != Drag::Invalid_3D_Point); } -#if ENABLE_EXTENDED_SELECTION GLCanvas3D::Selection::VolumeCache::VolumeCache() : m_position(Vec3d::Zero()) , m_rotation(Vec3d::Zero()) @@ -1918,7 +1910,6 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() } } } -#endif // ENABLE_EXTENDED_SELECTION const float GLCanvas3D::Gizmos::OverlayTexturesScale = 0.75f; const float GLCanvas3D::Gizmos::OverlayOffsetX = 10.0f * OverlayTexturesScale; @@ -2006,22 +1997,12 @@ void GLCanvas3D::Gizmos::set_enabled(bool enable) m_enabled = enable; } -#if ENABLE_EXTENDED_SELECTION std::string GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const GLCanvas3D::Selection& selection) -#else -void GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos) -#endif // ENABLE_EXTENDED_SELECTION { -#if ENABLE_EXTENDED_SELECTION std::string name = ""; -#endif // ENABLE_EXTENDED_SELECTION if (!m_enabled) -#if ENABLE_EXTENDED_SELECTION return name; -#else - return; -#endif // ENABLE_EXTENDED_SELECTION float cnv_h = (float)canvas.get_canvas_size().get_height(); float height = _get_total_overlay_height(); @@ -2035,32 +2016,20 @@ void GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Vec2 float half_tex_size = 0.5f * tex_size; // we currently use circular icons for gizmo, so we check the radius -#if ENABLE_EXTENDED_SELECTION if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On)) -#else - if (it->second->get_state() != GLGizmoBase::On) -#endif // ENABLE_EXTENDED_SELECTION { bool inside = (mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size; it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off); -#if ENABLE_EXTENDED_SELECTION if (inside) name = it->second->get_name(); -#endif // ENABLE_EXTENDED_SELECTION } top_y += (tex_size + OverlayGapY); } -#if ENABLE_EXTENDED_SELECTION return name; -#endif // ENABLE_EXTENDED_SELECTION } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const GLCanvas3D::Selection& selection) -#else -void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos) -#endif // ENABLE_EXTENDED_SELECTION { if (!m_enabled) return; @@ -2077,11 +2046,7 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec float half_tex_size = 0.5f * tex_size; // we currently use circular icons for gizmo, so we check the radius -#if ENABLE_EXTENDED_SELECTION if (it->second->is_activable(selection) && ((mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size)) -#else - if ((mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size) -#endif // ENABLE_EXTENDED_SELECTION { if ((it->second->get_state() == GLGizmoBase::On)) { @@ -2105,7 +2070,6 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec it->second->set_state(GLGizmoBase::On); } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::update_on_off_state(const Selection& selection) { GizmosMap::iterator it = m_gizmos.find(m_current); @@ -2118,7 +2082,6 @@ void GLCanvas3D::Gizmos::update_on_off_state(const Selection& selection) } } } -#endif // ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::reset_all_states() { @@ -2149,7 +2112,6 @@ void GLCanvas3D::Gizmos::set_hover_id(int id) } } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::enable_grabber(EType type, unsigned int id, bool enable) { if (!m_enabled) @@ -2164,7 +2126,6 @@ void GLCanvas3D::Gizmos::enable_grabber(EType type, unsigned int id, bool enable it->second->disable_grabber(id); } } -#endif // ENABLE_EXTENDED_SELECTION bool GLCanvas3D::Gizmos::overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const { @@ -2246,7 +2207,6 @@ bool GLCanvas3D::Gizmos::is_dragging() const return (curr != nullptr) ? curr->is_dragging() : false; } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::start_dragging(const GLCanvas3D::Selection& selection) { if (!m_enabled) @@ -2256,17 +2216,6 @@ void GLCanvas3D::Gizmos::start_dragging(const GLCanvas3D::Selection& selection) if (curr != nullptr) curr->start_dragging(selection); } -#else -void GLCanvas3D::Gizmos::start_dragging(const BoundingBoxf3& box) -{ - if (!m_enabled) - return; - - GLGizmoBase* curr = _get_current(); - if (curr != nullptr) - curr->start_dragging(box); -} -#endif // ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::stop_dragging() { @@ -2278,7 +2227,6 @@ void GLCanvas3D::Gizmos::stop_dragging() curr->stop_dragging(); } -#if ENABLE_EXTENDED_SELECTION Vec3d GLCanvas3D::Gizmos::get_displacement() const { if (!m_enabled) @@ -2287,26 +2235,6 @@ Vec3d GLCanvas3D::Gizmos::get_displacement() const GizmosMap::const_iterator it = m_gizmos.find(Move); return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_displacement() : Vec3d::Zero(); } -#else -Vec3d GLCanvas3D::Gizmos::get_position() const -{ - if (!m_enabled) - return Vec3d::Zero(); - - GizmosMap::const_iterator it = m_gizmos.find(Move); - return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_position() : Vec3d::Zero(); -} - -void GLCanvas3D::Gizmos::set_position(const Vec3d& position) -{ - if (!m_enabled) - return; - - GizmosMap::const_iterator it = m_gizmos.find(Move); - if (it != m_gizmos.end()) - reinterpret_cast(it->second)->set_position(position); -} -#endif // ENABLE_EXTENDED_SELECTION Vec3d GLCanvas3D::Gizmos::get_scale() const { @@ -2395,26 +2323,16 @@ void GLCanvas3D::Gizmos::delete_current_grabber(bool delete_all) reinterpret_cast(it->second)->delete_current_grabber(delete_all); } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::render_current_gizmo(const GLCanvas3D::Selection& selection) const -#else -void GLCanvas3D::Gizmos::render_current_gizmo(const BoundingBoxf3& box) const -#endif // ENABLE_EXTENDED_SELECTION { if (!m_enabled) return; ::glDisable(GL_DEPTH_TEST); -#if ENABLE_EXTENDED_SELECTION _render_current_gizmo(selection); -#else - if (box.radius() > 0.0) - _render_current_gizmo(box); -#endif // ENABLE_EXTENDED_SELECTION } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::render_current_gizmo_for_picking_pass(const GLCanvas3D::Selection& selection) const { if (!m_enabled) @@ -2424,17 +2342,6 @@ void GLCanvas3D::Gizmos::render_current_gizmo_for_picking_pass(const GLCanvas3D: if (curr != nullptr) curr->render_for_picking(selection); } -#else -void GLCanvas3D::Gizmos::render_current_gizmo_for_picking_pass(const BoundingBoxf3& box) const -{ - if (!m_enabled) - return; - - GLGizmoBase* curr = _get_current(); - if (curr != nullptr) - curr->render_for_picking(box); -} -#endif // ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::render_overlay(const GLCanvas3D& canvas) const { @@ -2485,21 +2392,12 @@ void GLCanvas3D::Gizmos::_render_overlay(const GLCanvas3D& canvas) const } } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::Gizmos::_render_current_gizmo(const GLCanvas3D::Selection& selection) const { GLGizmoBase* curr = _get_current(); if (curr != nullptr) curr->render(selection); } -#else -void GLCanvas3D::Gizmos::_render_current_gizmo(const BoundingBoxf3& box) const -{ - GLGizmoBase* curr = _get_current(); - if (curr != nullptr) - curr->render(box); -} -#endif // ENABLE_EXTENDED_SELECTION float GLCanvas3D::Gizmos::_get_total_overlay_height() const { @@ -2825,35 +2723,18 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const } wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); -#if ENABLE_EXTENDED_SELECTION wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); -#else -wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, ObjectSelectEvent); -#endif // ENABLE_EXTENDED_SELECTION wxDEFINE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); -#if !ENABLE_EXTENDED_SELECTION -wxDEFINE_EVENT(EVT_GLCANVAS_DOUBLE_CLICK, SimpleEvent); -#endif // !ENABLE_EXTENDED_SELECTION wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); wxDEFINE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); -#if !ENABLE_EXTENDED_SELECTION -wxDEFINE_EVENT(EVT_GLCANVAS_ROTATE_OBJECT, Event); -wxDEFINE_EVENT(EVT_GLCANVAS_SCALE_UNIFORMLY, SimpleEvent); -#endif // !ENABLE_EXTENDED_SELECTION wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); -#if !ENABLE_EXTENDED_SELECTION -wxDEFINE_EVENT(EVT_GIZMO_SCALE, Vec3dEvent); -wxDEFINE_EVENT(EVT_GIZMO_ROTATE, Vec3dEvent); -wxDEFINE_EVENT(EVT_GIZMO_FLATTEN, Vec3dEvent); -#endif // !ENABLE_EXTENDED_SELECTION - GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) : m_canvas(canvas) , m_context(nullptr) @@ -2875,14 +2756,8 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_shader_enabled(false) , m_dynamic_background_enabled(false) , m_multisample_allowed(false) -#if ENABLE_EXTENDED_SELECTION , m_regenerate_volumes(true) -#endif // ENABLE_EXTENDED_SELECTION , m_color_by("volume") -#if !ENABLE_EXTENDED_SELECTION - , m_select_by("object") - , m_drag_by("instance") -#endif // !ENABLE_EXTENDED_SELECTION , m_reload_delayed(false) { if (m_canvas != nullptr) @@ -2893,9 +2768,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) m_timer.SetOwner(m_canvas); } -#if ENABLE_EXTENDED_SELECTION m_selection.set_volumes(&m_volumes.volumes); -#endif // ENABLE_EXTENDED_SELECTION } GLCanvas3D::~GLCanvas3D() @@ -3028,9 +2901,7 @@ void GLCanvas3D::reset_volumes() return; #endif // !ENABLE_USE_UNIQUE_GLCONTEXT -#if ENABLE_EXTENDED_SELECTION m_selection.clear(); -#endif // ENABLE_EXTENDED_SELECTION m_volumes.release_geometry(); m_volumes.clear(); m_dirty = true; @@ -3040,48 +2911,6 @@ void GLCanvas3D::reset_volumes() _reset_warning_texture(); } -#if !ENABLE_EXTENDED_SELECTION -void GLCanvas3D::deselect_volumes() -{ - for (GLVolume* vol : m_volumes.volumes) - { - if (vol != nullptr) - vol->selected = false; - } -} - -void GLCanvas3D::select_volume(unsigned int id) -{ - if (id < (unsigned int)m_volumes.volumes.size()) - { - GLVolume* vol = m_volumes.volumes[id]; - if (vol != nullptr) - vol->selected = true; - } -} - -void GLCanvas3D::update_volumes_selection(const std::vector& selections) -{ - if (m_model == nullptr) - return; - - if (selections.empty()) - return; - - for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++obj_idx) - { - if ((selections[obj_idx] == 1) && (obj_idx < (unsigned int)m_objects_volumes_idxs.size())) - { - const std::vector& volume_idxs = m_objects_volumes_idxs[obj_idx]; - for (int v : volume_idxs) - { - select_volume(v); - } - } - } -} -#endif // !ENABLE_EXTENDED_SELECTION - int GLCanvas3D::check_volumes_outside_state(const DynamicPrintConfig* config) const { ModelInstance::EPrintVolumeState state; @@ -3095,10 +2924,6 @@ bool GLCanvas3D::move_volume_up(unsigned int id) { std::swap(m_volumes.volumes[id - 1], m_volumes.volumes[id]); std::swap(m_volumes.volumes[id - 1]->composite_id, m_volumes.volumes[id]->composite_id); -#if !ENABLE_EXTENDED_SELECTION - std::swap(m_volumes.volumes[id - 1]->select_group_id, m_volumes.volumes[id]->select_group_id); - std::swap(m_volumes.volumes[id - 1]->drag_group_id, m_volumes.volumes[id]->drag_group_id); -#endif // !ENABLE_EXTENDED_SELECTION return true; } @@ -3111,23 +2936,12 @@ bool GLCanvas3D::move_volume_down(unsigned int id) { std::swap(m_volumes.volumes[id + 1], m_volumes.volumes[id]); std::swap(m_volumes.volumes[id + 1]->composite_id, m_volumes.volumes[id]->composite_id); -#if !ENABLE_EXTENDED_SELECTION - std::swap(m_volumes.volumes[id + 1]->select_group_id, m_volumes.volumes[id]->select_group_id); - std::swap(m_volumes.volumes[id + 1]->drag_group_id, m_volumes.volumes[id]->drag_group_id); -#endif // !ENABLE_EXTENDED_SELECTION return true; } return false; } -#if !ENABLE_EXTENDED_SELECTION -void GLCanvas3D::set_objects_selections(const std::vector& selections) -{ - m_objects_selections = selections; -} -#endif // !ENABLE_EXTENDED_SELECTION - void GLCanvas3D::set_config(DynamicPrintConfig* config) { m_config = config; @@ -3141,9 +2955,7 @@ void GLCanvas3D::set_print(Print* print) void GLCanvas3D::set_model(Model* model) { m_model = model; -#if ENABLE_EXTENDED_SELECTION m_selection.set_model(m_model); -#endif // ENABLE_EXTENDED_SELECTION } void GLCanvas3D::set_bed_shape(const Pointfs& shape) @@ -3201,30 +3013,6 @@ void GLCanvas3D::set_color_by(const std::string& value) m_color_by = value; } -#if !ENABLE_EXTENDED_SELECTION -void GLCanvas3D::set_select_by(const std::string& value) -{ - m_select_by = value; - m_volumes.set_select_by(value); -} - -void GLCanvas3D::set_drag_by(const std::string& value) -{ - m_drag_by = value; - m_volumes.set_drag_by(value); -} - -const std::string& GLCanvas3D::get_select_by() const -{ - return m_select_by; -} - -const std::string& GLCanvas3D::get_drag_by() const -{ - return m_drag_by; -} -#endif // !ENABLE_EXTENDED_SELECTION - float GLCanvas3D::get_camera_zoom() const { return m_camera.zoom; @@ -3279,9 +3067,7 @@ void GLCanvas3D::enable_legend_texture(bool enable) void GLCanvas3D::enable_picking(bool enable) { m_picking_enabled = enable; -#if ENABLE_EXTENDED_SELECTION m_selection.set_mode(Selection::Instance); -#endif // ENABLE_EXTENDED_SELECTION } void GLCanvas3D::enable_moving(bool enable) @@ -3345,13 +3131,11 @@ void GLCanvas3D::zoom_to_volumes() } #if ENABLE_MODIFIED_CAMERA_TARGET -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::zoom_to_selection() { if (!m_selection.is_empty()) _zoom_to_bounding_box(m_selection.get_bounding_box()); } -#endif // ENABLE_EXTENDED_SELECTION #endif // ENABLE_MODIFIED_CAMERA_TARGET void GLCanvas3D::select_view(const std::string& direction) @@ -3405,7 +3189,6 @@ void GLCanvas3D::update_gizmos_data() if (!m_gizmos.is_enabled()) return; -#if ENABLE_EXTENDED_SELECTION bool enable_move_z = !m_selection.is_wipe_tower(); m_gizmos.enable_grabber(Gizmos::Move, 2, enable_move_z); bool enable_scale_xyz = m_selection.is_single_full_instance(); @@ -3429,32 +3212,6 @@ void GLCanvas3D::update_gizmos_data() m_gizmos.set_rotation(Vec3d::Zero()); m_gizmos.set_flattening_data(nullptr); } -#else - int id = _get_first_selected_object_id(); - if ((id != -1) && (m_model != nullptr)) - { - ModelObject* model_object = m_model->objects[id]; - if (model_object != nullptr) - { - ModelInstance* model_instance = model_object->instances[0]; - if (model_instance != nullptr) - { - m_gizmos.set_position(model_instance->get_offset()); - m_gizmos.set_scale(model_instance->get_scaling_factor()); - m_gizmos.set_rotation(model_instance->get_rotation()); - m_gizmos.set_flattening_data(model_object); - m_gizmos.set_model_object_ptr(model_object); - } - } - } - else - { - m_gizmos.set_position(Vec3d::Zero()); - m_gizmos.set_scale(Vec3d::Ones()); - m_gizmos.set_rotation(Vec3d::Zero()); - m_gizmos.set_flattening_data(nullptr); - } -#endif // ENABLE_EXTENDED_SELECTION } // Returns a Rect object denoting size and position of the Reset button used by a gizmo. @@ -3522,9 +3279,7 @@ void GLCanvas3D::render() } _render_objects(); -#if ENABLE_EXTENDED_SELECTION _render_selection(); -#endif // ENABLE_EXTENDED_SELECTION if (!is_custom_bed) // textured bed needs to be rendered after objects { @@ -3567,11 +3322,7 @@ std::vector GLCanvas3D::load_object(const ModelObject& model_object, int ob instance_idxs.push_back(i); } } -#if ENABLE_EXTENDED_SELECTION return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_use_VBOs && m_initialized); -#else - return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_select_by, m_drag_by, m_use_VBOs && m_initialized); -#endif // ENABLE_EXTENDED_SELECTION } std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) @@ -3602,31 +3353,24 @@ int GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const return ((0 <= scene_vol_idx) && (scene_vol_idx < (int)m_volumes.volumes.size())) ? m_volumes.volumes[scene_vol_idx]->volume_idx() : -1; } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::mirror_selection(Axis axis) { m_selection.mirror(axis); _on_mirror(); wxGetApp().obj_manipul()->update_settings_value(m_selection); } -#endif // ENABLE_EXTENDED_SELECTION void GLCanvas3D::reload_scene(bool force) { if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr)) return; -#if !ENABLE_EXTENDED_SELECTION - reset_volumes(); -#endif // !ENABLE_EXTENDED_SELECTION - #if !ENABLE_USE_UNIQUE_GLCONTEXT // ensures this canvas is current if (!set_current()) return; #endif // !ENABLE_USE_UNIQUE_GLCONTEXT -#if ENABLE_EXTENDED_SELECTION if (m_regenerate_volumes) { reset_volumes(); @@ -3634,7 +3378,6 @@ void GLCanvas3D::reload_scene(bool force) // to update the toolbar post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); } -#endif // ENABLE_EXTENDED_SELECTION set_bed_shape(dynamic_cast(m_config->option("bed_shape"))->values); @@ -3646,7 +3389,6 @@ void GLCanvas3D::reload_scene(bool force) m_reload_delayed = false; -#if ENABLE_EXTENDED_SELECTION if (m_regenerate_volumes) { for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++obj_idx) @@ -3656,26 +3398,9 @@ void GLCanvas3D::reload_scene(bool force) } update_gizmos_data(); -#else - m_objects_volumes_idxs.clear(); - for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++obj_idx) - { - m_objects_volumes_idxs.push_back(load_object(*m_model, obj_idx)); - } - - // 1st call to reset if no objects left - update_gizmos_data(); - update_volumes_selection(m_objects_selections); - // 2nd call to restore selection, if any - if (!m_objects_selections.empty()) - update_gizmos_data(); -#endif // ENABLE_EXTENDED_SELECTION - -#if ENABLE_EXTENDED_SELECTION if (m_regenerate_volumes) { -#endif // ENABLE_EXTENDED_SELECTION if (m_config->has("nozzle_diameter")) { // Should the wipe tower be visualized ? @@ -3705,9 +3430,7 @@ void GLCanvas3D::reload_scene(bool force) } update_volumes_colors_by_extruder(); -#if ENABLE_EXTENDED_SELECTION } -#endif // ENABLE_EXTENDED_SELECTION // checks for geometry outside the print volume to render it accordingly if (!m_volumes.empty()) @@ -3736,10 +3459,8 @@ void GLCanvas3D::reload_scene(bool force) post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false)); } -#if ENABLE_EXTENDED_SELECTION // restore to default value m_regenerate_volumes = true; -#endif // ENABLE_EXTENDED_SELECTION } void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const std::vector& str_tool_colors) @@ -3903,19 +3624,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) // key B/b case 66: case 98: { zoom_to_bed(); break; } -#if !ENABLE_EXTENDED_SELECTION - // key L/l - case 76: - case 108: { post_event(Event(EVT_GLCANVAS_ROTATE_OBJECT, -1)); break; } - // key R/r - case 82: - case 114: { post_event(Event(EVT_GLCANVAS_ROTATE_OBJECT, +1)); break; } - // key S/s - case 83: - case 115: { post_event(SimpleEvent(EVT_GLCANVAS_SCALE_UNIFORMLY)); break; } -#endif // !ENABLE_EXTENDED_SELECTION #if ENABLE_MODIFIED_CAMERA_TARGET -#if ENABLE_EXTENDED_SELECTION // key Z/z case 90: case 122: @@ -3927,11 +3636,6 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; } -#else - // key Z/z - case 90: - case 122: { zoom_to_volumes(); break; } -#endif // ENABLE_EXTENDED_SELECTION #else // key Z/z case 90: @@ -3957,11 +3661,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) // Performs layers editing updates, if enabled if (is_layers_editing_enabled()) { -#if ENABLE_EXTENDED_SELECTION int object_idx_selected = m_selection.get_object_idx(); -#else - int object_idx_selected = _get_first_selected_object_id(); -#endif // ENABLE_EXTENDED_SELECTION if (object_idx_selected != -1) { // A volume is selected. Test, whether hovering over a layer thickness bar. @@ -4005,13 +3705,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { Point pos(evt.GetX(), evt.GetY()); -#if ENABLE_EXTENDED_SELECTION int selected_object_idx = m_selection.get_object_idx(); int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1; -#else - int selected_object_idx = _get_first_selected_object_id(); - int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1; -#endif // ENABLE_EXTENDED_SELECTION m_layers_editing.last_object_id = layer_editing_object_idx; bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position); int toolbar_contains_mouse = m_toolbar.contains_mouse(m_mouse.position); @@ -4032,10 +3727,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.position = Vec2d(-1.0, -1.0); m_dirty = true; } -#if !ENABLE_EXTENDED_SELECTION - else if (evt.LeftDClick() && (m_hover_volume_id != -1) && !gizmos_overlay_contains_mouse && (toolbar_contains_mouse == -1)) - post_event(SimpleEvent(EVT_GLCANVAS_DOUBLE_CLICK)); -#endif // !ENABLE_EXTENDED_SELECTION else if (evt.LeftDClick() && (toolbar_contains_mouse != -1)) { m_toolbar_action_running = true; @@ -4050,33 +3741,17 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { case Gizmos::Scale: { -#if ENABLE_EXTENDED_SELECTION m_selection.scale(m_gizmos.get_scale()); _on_scale(); -#else - post_event(Vec3dEvent(EVT_GIZMO_SCALE, m_gizmos.get_scale())); -#endif // ENABLE_EXTENDED_SELECTION -#if ENABLE_EXTENDED_SELECTION wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - wxGetApp().obj_manipul()->update_scale_values(); -#endif // ENABLE_EXTENDED_SELECTION m_dirty = true; break; } case Gizmos::Rotate: { -#if ENABLE_EXTENDED_SELECTION m_selection.rotate(m_gizmos.get_rotation()); _on_rotate(); -#else - post_event(Vec3dEvent(EVT_GIZMO_ROTATE, std::move(m_gizmos.get_rotation()))); -#endif // ENABLE_EXTENDED_SELECTION -#if ENABLE_EXTENDED_SELECTION wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - wxGetApp().obj_manipul()->update_rotation_values(); -#endif // ENABLE_EXTENDED_SELECTION m_dirty = true; break; } @@ -4091,9 +3766,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { // If user pressed left or right button we first check whether this happened // on a volume or not. -#if !ENABLE_EXTENDED_SELECTION - int volume_idx = m_hover_volume_id; -#endif // !ENABLE_EXTENDED_SELECTION m_layers_editing.state = LayersEditing::Unknown; if ((layer_editing_object_idx != -1) && m_layers_editing.bar_rect_contains(*this, pos(0), pos(1))) { @@ -4127,45 +3799,23 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } } -#if ENABLE_EXTENDED_SELECTION else if (!m_selection.is_empty() && gizmos_overlay_contains_mouse) { m_gizmos.update_on_off_state(*this, m_mouse.position, m_selection); update_gizmos_data(); m_dirty = true; } -#else - else if ((selected_object_idx != -1) && gizmos_overlay_contains_mouse) - { - update_gizmos_data(); - m_gizmos.update_on_off_state(*this, m_mouse.position); - m_dirty = true; - } -#endif // ENABLE_EXTENDED_SELECTION -#if ENABLE_EXTENDED_SELECTION else if (evt.LeftDown() && !m_selection.is_empty() && m_gizmos.grabber_contains_mouse()) -#else - else if (evt.LeftDown() && (selected_object_idx != -1) && m_gizmos.grabber_contains_mouse()) -#endif // ENABLE_EXTENDED_SELECTION { update_gizmos_data(); -#if ENABLE_EXTENDED_SELECTION m_selection.start_dragging(); m_gizmos.start_dragging(m_selection); -#else - m_gizmos.start_dragging(_selected_volumes_bounding_box()); - m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx); -#endif // ENABLE_EXTENDED_SELECTION if (m_gizmos.get_current_type() == Gizmos::Flatten) { // Rotate the object so the normal points downward: -#if ENABLE_EXTENDED_SELECTION m_selection.rotate(m_gizmos.get_flattening_rotation()); _on_flatten(); wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - post_event(Vec3dEvent(EVT_GIZMO_FLATTEN, m_gizmos.get_flattening_rotation())); -#endif // ENABLE_EXTENDED_SELECTION } m_dirty = true; @@ -4185,13 +3835,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // Don't deselect a volume if layer editing is enabled. We want the object to stay selected // during the scene manipulation. -#if ENABLE_EXTENDED_SELECTION if (m_picking_enabled && ((m_hover_volume_id != -1) || !is_layers_editing_enabled())) -#else - if (m_picking_enabled && ((volume_idx != -1) || !is_layers_editing_enabled())) -#endif // ENABLE_EXTENDED_SELECTION { -#if ENABLE_EXTENDED_SELECTION if (evt.LeftDown() && (m_hover_volume_id != -1)) { bool already_selected = m_selection.contains_volume(m_hover_volume_id); @@ -4211,76 +3856,27 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); m_dirty = true; } -#else - if (volume_idx != -1) - { - deselect_volumes(); - select_volume(volume_idx); - int group_id = m_volumes.volumes[volume_idx]->select_group_id; - if (group_id != -1) - { - for (GLVolume* vol : m_volumes.volumes) - { - if ((vol != nullptr) && (vol->select_group_id == group_id)) - vol->selected = true; - } - } - - update_gizmos_data(); - m_dirty = true; - } -#endif // ENABLE_EXTENDED_SELECTION } // propagate event through callback -#if !ENABLE_EXTENDED_SELECTION - if (m_picking_enabled && (volume_idx != -1)) - _on_select(volume_idx, selected_object_idx); -#endif // !ENABLE_EXTENDED_SELECTION -#if ENABLE_EXTENDED_SELECTION if (m_hover_volume_id != -1) -#else - if (volume_idx != -1) -#endif // ENABLE_EXTENDED_SELECTION { -#if ENABLE_EXTENDED_SELECTION if (evt.LeftDown() && m_moving_enabled && (m_mouse.drag.move_volume_idx == -1)) -#else - if (evt.LeftDown() && m_moving_enabled) -#endif // ENABLE_EXTENDED_SELECTION { // The mouse_to_3d gets the Z coordinate from the Z buffer at the screen coordinate pos x, y, // an converts the screen space coordinate to unscaled object space. -#if ENABLE_EXTENDED_SELECTION Vec3d pos3d = _mouse_to_3d(pos); -#else - Vec3d pos3d = (volume_idx == -1) ? Vec3d(DBL_MAX, DBL_MAX, DBL_MAX) : _mouse_to_3d(pos); -#endif // Only accept the initial position, if it is inside the volume bounding box. -#if ENABLE_EXTENDED_SELECTION BoundingBoxf3 volume_bbox = m_volumes.volumes[m_hover_volume_id]->transformed_bounding_box(); -#else - BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box(); -#endif // ENABLE_EXTENDED_SELECTION volume_bbox.offset(1.0); if (volume_bbox.contains(pos3d)) { // The dragging operation is initiated. -#if ENABLE_EXTENDED_SELECTION m_mouse.drag.move_volume_idx = m_hover_volume_id; m_selection.start_dragging(); -#else - m_mouse.drag.move_with_shift = evt.ShiftDown(); - m_mouse.drag.move_volume_idx = volume_idx; -#endif // ENABLE_EXTENDED_SELECTION m_mouse.drag.start_position_3D = pos3d; -#if !ENABLE_EXTENDED_SELECTION - // Remember the shift to to the object center.The object center will later be used - // to limit the object placement close to the bed. - m_mouse.drag.volume_center_offset = volume_bbox.center() - pos3d; -#endif // !ENABLE_EXTENDED_SELECTION } } else if (evt.RightDown()) @@ -4291,7 +3887,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) render(); if (m_hover_volume_id != -1) { -#if ENABLE_EXTENDED_SELECTION // if right clicking on volume, propagate event through callback (shows context menu) if (m_volumes.volumes[m_hover_volume_id]->hover && !m_volumes.volumes[m_hover_volume_id]->is_wipe_tower) { @@ -4305,11 +3900,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) render(); post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, pos.cast())); } -#else - // if right clicking on volume, propagate event through callback (shows context menu) - if (m_volumes.volumes[volume_idx]->hover) - post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, pos.cast())); -#endif // ENABLE_EXTENDED_SELECTION } } } @@ -4322,60 +3912,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // Get new position at the same Z of the initial click point. float z0 = 0.0f; float z1 = 1.0f; -#if ENABLE_EXTENDED_SELECTION // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag Vec3d cur_pos = m_selection.contains_volume(m_hover_volume_id) ? Linef3(_mouse_to_3d(pos, &z0), _mouse_to_3d(pos, &z1)).intersect_plane(m_mouse.drag.start_position_3D(2)) : m_mouse.drag.start_position_3D; -#else - Vec3d cur_pos = Linef3(_mouse_to_3d(pos, &z0), _mouse_to_3d(pos, &z1)).intersect_plane(m_mouse.drag.start_position_3D(2)); -#endif // ENABLE_EXTENDED_SELECTION - -#if !ENABLE_EXTENDED_SELECTION - // Clip the new position, so the object center remains close to the bed. - cur_pos += m_mouse.drag.volume_center_offset; - Point cur_pos2(scale_(cur_pos(0)), scale_(cur_pos(1))); - if (!m_bed.contains(cur_pos2)) - { - Point ip = m_bed.point_projection(cur_pos2); - cur_pos(0) = unscale(ip(0)); - cur_pos(1) = unscale(ip(1)); - } - cur_pos -= m_mouse.drag.volume_center_offset; -#endif // !ENABLE_EXTENDED_SELECTION // Calculate the translation vector. Vec3d displacement = cur_pos - m_mouse.drag.start_position_3D; -#if ENABLE_EXTENDED_SELECTION m_selection.translate(displacement); wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - // Get the volume being dragged. - GLVolume* volume = m_volumes.volumes[m_mouse.drag.move_volume_idx]; - // Get all volumes belonging to the same group, if any. - std::vector volumes; - int group_id = m_mouse.drag.move_with_shift ? volume->select_group_id : volume->drag_group_id; - if (group_id == -1) - volumes.push_back(volume); - else - { - for (GLVolume* v : m_volumes.volumes) - { - if (v != nullptr) - { - if ((m_mouse.drag.move_with_shift && (v->select_group_id == group_id)) || (!m_mouse.drag.move_with_shift && (v->drag_group_id == group_id))) - volumes.push_back(v); - } - } - } - - // Apply new temporary volume origin and ignore Z. - for (GLVolume* v : volumes) - { - v->set_offset(v->get_offset() + Vec3d(displacement(0), displacement(1), 0.0)); - } - - wxGetApp().obj_manipul()->update_position_value(volume->get_offset()); - m_mouse.drag.start_position_3D = cur_pos; -#endif // ENABLE_EXTENDED_SELECTION m_dirty = true; } @@ -4387,95 +3930,44 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.dragging = true; m_gizmos.update(mouse_ray(pos), &pos); -#if !ENABLE_EXTENDED_SELECTION - std::vector volumes; - if (m_mouse.drag.gizmo_volume_idx != -1) - { - GLVolume* volume = m_volumes.volumes[m_mouse.drag.gizmo_volume_idx]; - // Get all volumes belonging to the same group, if any. - if (volume->select_group_id == -1) - volumes.push_back(volume); - else - { - for (GLVolume* v : m_volumes.volumes) - { - if ((v != nullptr) && (v->select_group_id == volume->select_group_id)) - volumes.push_back(v); - } - } - } -#endif // !ENABLE_EXTENDED_SELECTION - switch (m_gizmos.get_current_type()) { case Gizmos::Move: { // Apply new temporary offset -#if ENABLE_EXTENDED_SELECTION m_selection.translate(m_gizmos.get_displacement()); wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - GLVolume* volume = m_volumes.volumes[m_mouse.drag.gizmo_volume_idx]; - Vec3d offset = m_gizmos.get_position() - volume->get_offset(); - for (GLVolume* v : volumes) - { - v->set_offset(v->get_offset() + offset); - } - wxGetApp().obj_manipul()->update_position_value(volume->get_offset()); -#endif // ENABLE_EXTENDED_SELECTION break; } case Gizmos::Scale: { // Apply new temporary scale factors -#if ENABLE_EXTENDED_SELECTION m_selection.scale(m_gizmos.get_scale()); wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - const Vec3d& scale = m_gizmos.get_scale(); - for (GLVolume* v : volumes) - { - v->set_scaling_factor(scale); - } - wxGetApp().obj_manipul()->update_scale_value(scale); -#endif // ENABLE_EXTENDED_SELECTION break; } case Gizmos::Rotate: { // Apply new temporary rotations -#if ENABLE_EXTENDED_SELECTION m_selection.rotate(m_gizmos.get_rotation()); wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - // Apply new temporary rotation - const Vec3d& rotation = m_gizmos.get_rotation(); - for (GLVolume* v : volumes) - { - v->set_rotation(rotation); - } - wxGetApp().obj_manipul()->update_rotation_value(rotation); -#endif // ENABLE_EXTENDED_SELECTION break; } default: break; } -#if ENABLE_EXTENDED_SELECTION -#else - if (!volumes.empty()) - { - BoundingBoxf3 bb; - for (const GLVolume* volume : volumes) - { - bb.merge(volume->transformed_bounding_box()); - } - const Vec3d& size = bb.size(); - const Vec3d& scale = m_gizmos.get_scale(); - post_event(Vec3dsEvent<2>(EVT_GLCANVAS_UPDATE_GEOMETRY, {size, scale})); - } -#endif // ENABLE_EXTENDED_SELECTION +// if (!volumes.empty()) +// { +// BoundingBoxf3 bb; +// for (const GLVolume* volume : volumes) +// { +// bb.merge(volume->transformed_bounding_box()); +// } +// const Vec3d& size = bb.size(); +// const Vec3d& scale = m_gizmos.get_scale(); +// post_event(Vec3dsEvent<2>(EVT_GLCANVAS_UPDATE_GEOMETRY, {size, scale})); +// } m_dirty = true; } @@ -4534,40 +4026,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging) { -#if ENABLE_EXTENDED_SELECTION m_regenerate_volumes = false; _on_move(); wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - // get all volumes belonging to the same group, if any - std::vector volume_idxs; - int vol_id = m_mouse.drag.move_volume_idx; - int group_id = m_mouse.drag.move_with_shift ? m_volumes.volumes[vol_id]->select_group_id : m_volumes.volumes[vol_id]->drag_group_id; - if (group_id == -1) - volume_idxs.push_back(vol_id); - else - { - for (int i = 0; i < (int)m_volumes.volumes.size(); ++i) - { - if ((m_mouse.drag.move_with_shift && (m_volumes.volumes[i]->select_group_id == group_id)) || (m_volumes.volumes[i]->drag_group_id == group_id)) - volume_idxs.push_back(i); - } - } - - _on_move(volume_idxs); - - // force re-selection of the wipe tower, if needed - if ((volume_idxs.size() == 1) && m_volumes.volumes[volume_idxs[0]]->is_wipe_tower) - select_volume(volume_idxs[0]); -#endif // ENABLE_EXTENDED_SELECTION } else if (m_gizmos.get_current_type() == Gizmos::SlaSupports && m_hover_volume_id != -1) { -#if ENABLE_EXTENDED_SELECTION int id = m_selection.get_object_idx(); -#else - int id = _get_first_selected_object_id(); -#endif // ENABLE_EXTENDED_SELECTION if ((id != -1) && (m_model != nullptr)) { m_gizmos.clicked_on_object(Vec2d(pos(0), pos(1))); @@ -4582,14 +4047,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_picking_enabled && !m_toolbar_action_running) #endif // ENABLE_GIZMOS_RESET { -#if ENABLE_EXTENDED_SELECTION m_selection.clear(); wxGetApp().obj_manipul()->update_settings_value(m_selection); post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); -#else - deselect_volumes(); - _on_select(-1, -1); -#endif // ENABLE_EXTENDED_SELECTION update_gizmos_data(); } #if ENABLE_GIZMOS_RESET @@ -4603,61 +4063,28 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { case Gizmos::Move: { -#if ENABLE_EXTENDED_SELECTION m_regenerate_volumes = false; _on_move(); -#else - // get all volumes belonging to the same group, if any - std::vector volume_idxs; - int vol_id = m_mouse.drag.gizmo_volume_idx; - int group_id = m_volumes.volumes[vol_id]->select_group_id; - if (group_id == -1) - volume_idxs.push_back(vol_id); - else - { - for (int i = 0; i < (int)m_volumes.volumes.size(); ++i) - { - if (m_volumes.volumes[i]->select_group_id == group_id) - volume_idxs.push_back(i); - } - } - - _on_move(volume_idxs); -#endif // ENABLE_EXTENDED_SELECTION - break; } case Gizmos::Scale: { -#if ENABLE_EXTENDED_SELECTION _on_scale(); -#endif // ENABLE_EXTENDED_SELECTION break; } case Gizmos::Rotate: { -#if ENABLE_EXTENDED_SELECTION _on_rotate(); -#else - post_event(Vec3dEvent(EVT_GIZMO_ROTATE, m_gizmos.get_rotation())); -#endif // ENABLE_EXTENDED_SELECTION break; } default: break; } m_gizmos.stop_dragging(); -#if ENABLE_EXTENDED_SELECTION wxGetApp().obj_manipul()->update_settings_value(m_selection); -#else - wxGetApp().obj_manipul()->update_values(); -#endif // ENABLE_EXTENDED_SELECTION } m_mouse.drag.move_volume_idx = -1; -#if !ENABLE_EXTENDED_SELECTION - m_mouse.drag.gizmo_volume_idx = -1; -#endif // !ENABLE_EXTENDED_SELECTION m_mouse.set_start_position_3D_as_invalid(); m_mouse.set_start_position_2D_as_invalid(); m_mouse.dragging = false; @@ -4859,16 +4286,6 @@ bool GLCanvas3D::_init_toolbar() if (!m_toolbar.add_separator()) return false; -#if !ENABLE_EXTENDED_SELECTION - item.name = "settings"; - item.tooltip = GUI::L_str("Settings..."); - item.sprite_id = 8; - item.is_toggable = false; - item.action_event = EVT_GLTOOLBAR_SETTINGS; - if (!m_toolbar.add_item(item)) - return false; -#endif // !ENABLE_EXTENDED_SELECTION - item.name = "layersediting"; item.tooltip = GUI::L_str("Layers editing"); item.sprite_id = 9; @@ -4880,16 +4297,6 @@ bool GLCanvas3D::_init_toolbar() if (!m_toolbar.add_separator()) return false; -#if !ENABLE_EXTENDED_SELECTION - item.name = "selectbyparts"; - item.tooltip = GUI::L_str("Select by parts"); - item.sprite_id = 10; - item.is_toggable = true; - item.action_event = EVT_GLTOOLBAR_SELECTBYPARTS; - if (!m_toolbar.add_item(item)) - return false; -#endif // !ENABLE_EXTENDED_SELECTION - enable_toolbar_item("add", true); return true; @@ -4984,53 +4391,6 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box() const return bb; } -#if !ENABLE_EXTENDED_SELECTION -BoundingBoxf3 GLCanvas3D::_selected_volumes_bounding_box() const -{ - BoundingBoxf3 bb; - - std::vector selected_volumes; - for (const GLVolume* volume : m_volumes.volumes) - { - if ((volume != nullptr) && !volume->is_wipe_tower && volume->selected) - selected_volumes.push_back(volume); - } - - bool use_drag_group_id = selected_volumes.size() > 1; - if (use_drag_group_id) - { - int drag_group_id = selected_volumes[0]->drag_group_id; - for (const GLVolume* volume : selected_volumes) - { - if (drag_group_id != volume->drag_group_id) - { - use_drag_group_id = false; - break; - } - } - } - - if (use_drag_group_id) - { - for (const GLVolume* volume : selected_volumes) - { - bb.merge(volume->bounding_box); - } - - bb = bb.transformed(selected_volumes[0]->world_matrix().cast()); - } - else - { - for (const GLVolume* volume : selected_volumes) - { - bb.merge(volume->transformed_bounding_box()); - } - } - - return bb; -} -#endif // !ENABLE_EXTENDED_SELECTION - void GLCanvas3D::_zoom_to_bounding_box(const BoundingBoxf3& bbox) { // Calculate the zoom factor needed to adjust viewport to bounding box. @@ -5121,11 +4481,7 @@ void GLCanvas3D::_mark_volumes_for_layer_height() const for (GLVolume* vol : m_volumes.volumes) { -#if ENABLE_EXTENDED_SELECTION int object_id = vol->object_idx(); -#else - int object_id = int(vol->select_group_id / 1000000); -#endif // ENABLE_EXTENDED_SELECTION int shader_id = m_layers_editing.get_shader_program_id(); if (is_layers_editing_enabled() && (shader_id != -1) && vol->selected && @@ -5180,22 +4536,12 @@ void GLCanvas3D::_picking_pass() const ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _render_volumes(true); -#if ENABLE_EXTENDED_SELECTION m_gizmos.render_current_gizmo_for_picking_pass(m_selection); -#else - m_gizmos.render_current_gizmo_for_picking_pass(_selected_volumes_bounding_box()); -#endif // ENABLE_EXTENDED_SELECTION if (m_multisample_allowed) ::glEnable(GL_MULTISAMPLE); int volume_id = -1; -#if !ENABLE_EXTENDED_SELECTION - for (GLVolume* vol : m_volumes.volumes) - { - vol->hover = false; - } -#endif // !ENABLE_EXTENDED_SELECTION GLubyte color[4] = { 0, 0, 0, 0 }; const Size& cnv_size = get_canvas_size(); @@ -5209,18 +4555,6 @@ void GLCanvas3D::_picking_pass() const if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) { m_hover_volume_id = volume_id; -#if !ENABLE_EXTENDED_SELECTION - m_volumes.volumes[volume_id]->hover = true; - int group_id = m_volumes.volumes[volume_id]->select_group_id; - if (group_id != -1) - { - for (GLVolume* vol : m_volumes.volumes) - { - if (vol->select_group_id == group_id) - vol->hover = true; - } - } -#endif // !ENABLE_EXTENDED_SELECTION m_gizmos.set_hover_id(-1); } else @@ -5229,22 +4563,15 @@ void GLCanvas3D::_picking_pass() const m_gizmos.set_hover_id(inside ? (254 - (int)color[2]) : -1); } -#if ENABLE_EXTENDED_SELECTION _update_volumes_hover_state(); -#endif // ENABLE_EXTENDED_SELECTION // updates gizmos overlay -#if ENABLE_EXTENDED_SELECTION if (!m_selection.is_empty()) { std::string name = m_gizmos.update_hover_state(*this, pos, m_selection); if (!name.empty()) set_tooltip(name); } -#else - if (_get_first_selected_object_id() != -1) - m_gizmos.update_hover_state(*this, pos); -#endif // ENABLE_EXTENDED_SELECTION else m_gizmos.reset_all_states(); @@ -5344,14 +4671,12 @@ void GLCanvas3D::_render_objects() const ::glDisable(GL_LIGHTING); } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::_render_selection() const { Gizmos::EType type = m_gizmos.get_current_type(); bool show_indirect_selection = m_gizmos.is_running() && ((type == Gizmos::Rotate) || (type == Gizmos::Scale) || (type == Gizmos::Flatten)); m_selection.render(show_indirect_selection); } -#endif // ENABLE_EXTENDED_SELECTION void GLCanvas3D::_render_cutting_plane() const { @@ -5395,11 +4720,7 @@ void GLCanvas3D::_render_layer_editing_overlay() const // If the active object was not allocated at the Print, go away.This should only be a momentary case between an object addition / deletion // and an update by Platter::async_apply_config. -#if ENABLE_EXTENDED_SELECTION int object_idx = volume->object_idx(); -#else - int object_idx = int(volume->select_group_id / 1000000); -#endif // ENABLE_EXTENDED_SELECTION if ((int)m_print->objects().size() <= object_idx) return; @@ -5459,11 +4780,7 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const void GLCanvas3D::_render_current_gizmo() const { -#if ENABLE_EXTENDED_SELECTION m_gizmos.render_current_gizmo(m_selection); -#else - m_gizmos.render_current_gizmo(_selected_volumes_bounding_box()); -#endif // ENABLE_EXTENDED_SELECTION } void GLCanvas3D::_render_gizmos_overlay() const @@ -5504,7 +4821,6 @@ void GLCanvas3D::_render_camera_target() const } #endif // ENABLE_SHOW_CAMERA_TARGET -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::_update_volumes_hover_state() const { for (GLVolume* v : m_volumes.volumes) @@ -5539,7 +4855,6 @@ void GLCanvas3D::_update_volumes_hover_state() const } } } -#endif // ENABLE_EXTENDED_SELECTION float GLCanvas3D::_get_layers_editing_cursor_z_relative() const { @@ -5643,42 +4958,6 @@ void GLCanvas3D::_stop_timer() m_timer.Stop(); } -#if !ENABLE_EXTENDED_SELECTION -int GLCanvas3D::_get_first_selected_object_id() const -{ - if (m_print != nullptr) - { - int objects_count = (int)m_print->objects().size(); - - for (const GLVolume* vol : m_volumes.volumes) - { - if ((vol != nullptr) && vol->selected) - { - int object_id = vol->select_group_id / 1000000; - // Objects with object_id >= 1000 have a specific meaning, for example the wipe tower proxy. - if (object_id < 10000) - return (object_id >= objects_count) ? -1 : object_id; - } - } - } - return -1; -} - -int GLCanvas3D::_get_first_selected_volume_id(int object_id) const -{ - int volume_id = -1; - - for (const GLVolume* vol : m_volumes.volumes) - { - ++volume_id; - if ((vol != nullptr) && vol->selected && (object_id == vol->select_group_id / 1000000)) - return volume_id; - } - - return -1; -} -#endif // !ENABLE_EXTENDED_SELECTION - void GLCanvas3D::_load_print_toolpaths() { #if !ENABLE_USE_UNIQUE_GLCONTEXT @@ -5806,11 +5085,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c tbb::parallel_for( tbb::blocked_range(0, ctxt.layers.size(), grain_size), [&ctxt, &new_volume](const tbb::blocked_range& range) { -#if ENABLE_EXTENDED_SELECTION GLVolumePtrs vols; -#else - std::vector vols; -#endif // ENABLE_EXTENDED_SELECTION if (ctxt.color_by_tool()) { for (size_t i = 0; i < ctxt.number_tools(); ++i) vols.emplace_back(new_volume(ctxt.color_tool(i))); @@ -5969,11 +5244,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_ tbb::blocked_range(0, n_items, grain_size), [&ctxt, &new_volume](const tbb::blocked_range& range) { // Bounding box of this slab of a wipe tower. -#if ENABLE_EXTENDED_SELECTION GLVolumePtrs vols; -#else - std::vector vols; -#endif // ENABLE_EXTENDED_SELECTION if (ctxt.color_by_tool()) { for (size_t i = 0; i < ctxt.number_tools(); ++i) vols.emplace_back(new_volume(ctxt.color_tool(i))); @@ -6199,15 +5470,9 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat m_gcode_preview_volume_index.first_volumes.pop_back(); if (initial_volumes_count != m_volumes.volumes.size()) { -#if ENABLE_EXTENDED_SELECTION GLVolumePtrs::iterator begin = m_volumes.volumes.begin() + initial_volumes_count; GLVolumePtrs::iterator end = m_volumes.volumes.end(); for (GLVolumePtrs::iterator it = begin; it < end; ++it) -#else - std::vector::iterator begin = m_volumes.volumes.begin() + initial_volumes_count; - std::vector::iterator end = m_volumes.volumes.end(); - for (std::vector::iterator it = begin; it < end; ++it) -#endif // ENABLE_EXTENDED_SELECTION { GLVolume* volume = *it; delete volume; @@ -6278,15 +5543,9 @@ void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data, // an error occourred - restore to previous state and return if (initial_volumes_count != m_volumes.volumes.size()) { -#if ENABLE_EXTENDED_SELECTION GLVolumePtrs::iterator begin = m_volumes.volumes.begin() + initial_volumes_count; GLVolumePtrs::iterator end = m_volumes.volumes.end(); for (GLVolumePtrs::iterator it = begin; it < end; ++it) -#else - std::vector::iterator begin = m_volumes.volumes.begin() + initial_volumes_count; - std::vector::iterator end = m_volumes.volumes.end(); - for (std::vector::iterator it = begin; it < end; ++it) -#endif // ENABLE_EXTENDED_SELECTION { GLVolume* volume = *it; delete volume; @@ -6590,11 +5849,7 @@ void GLCanvas3D::_load_shells() instance_ids[i] = i; } -#if ENABLE_EXTENDED_SELECTION m_volumes.load_object(model_obj, object_id, instance_ids, "object", m_use_VBOs && m_initialized); -#else - m_volumes.load_object(model_obj, object_id, instance_ids, "object", "object", "object", m_use_VBOs && m_initialized); -#endif // ENABLE_EXTENDED_SELECTION ++object_id; } @@ -6617,17 +5872,10 @@ void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& previe unsigned int size = (unsigned int)m_gcode_preview_volume_index.first_volumes.size(); for (unsigned int i = 0; i < size; ++i) { -#if ENABLE_EXTENDED_SELECTION GLVolumePtrs::iterator begin = m_volumes.volumes.begin() + m_gcode_preview_volume_index.first_volumes[i].id; GLVolumePtrs::iterator end = (i + 1 < size) ? m_volumes.volumes.begin() + m_gcode_preview_volume_index.first_volumes[i + 1].id : m_volumes.volumes.end(); for (GLVolumePtrs::iterator it = begin; it != end; ++it) -#else - std::vector::iterator begin = m_volumes.volumes.begin() + m_gcode_preview_volume_index.first_volumes[i].id; - std::vector::iterator end = (i + 1 < size) ? m_volumes.volumes.begin() + m_gcode_preview_volume_index.first_volumes[i + 1].id : m_volumes.volumes.end(); - - for (std::vector::iterator it = begin; it != end; ++it) -#endif // ENABLE_EXTENDED_SELECTION { GLVolume* volume = *it; @@ -6716,7 +5964,6 @@ void GLCanvas3D::_show_warning_texture_if_needed() } } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3D::_on_move() { if (m_model == nullptr) @@ -6893,87 +6140,6 @@ void GLCanvas3D::_on_mirror() post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } -#else -void GLCanvas3D::_on_move(const std::vector& volume_idxs) -{ - if (m_model == nullptr) - return; - - std::set done; // prevent moving instances twice - bool object_moved = false; - Vec3d wipe_tower_origin = Vec3d::Zero(); - for (int volume_idx : volume_idxs) - { - GLVolume* volume = m_volumes.volumes[volume_idx]; - int obj_idx = volume->object_idx(); - int instance_idx = volume->instance_idx(); - - // prevent moving instances twice - char done_id[64]; - ::sprintf(done_id, "%d_%d", obj_idx, instance_idx); - if (done.find(done_id) != done.end()) - continue; - - done.insert(done_id); - - if (obj_idx < 1000) - { - // Move a regular object. - ModelObject* model_object = m_model->objects[obj_idx]; - if (model_object != nullptr) - { - model_object->instances[instance_idx]->set_offset(volume->get_offset()); - model_object->invalidate_bounding_box(); - wxGetApp().obj_manipul()->update_position_values(); - object_moved = true; - } - } - else if (obj_idx == 1000) - // Move a wipe tower proxy. - wipe_tower_origin = volume->get_offset(); - } - - if (object_moved) - post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED)); - - if (wipe_tower_origin != Vec3d::Zero()) - post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin))); -} -#endif // ENABLE_EXTENDED_SELECTION - -#if !ENABLE_EXTENDED_SELECTION -void GLCanvas3D::_on_select(int volume_idx, int object_idx) -{ - int vol_id = -1; - int obj_id = -1; - - if ((volume_idx != -1) && (volume_idx < (int)m_volumes.volumes.size())) - { - if (m_select_by == "volume") - { - if (m_volumes.volumes[volume_idx]->object_idx() != object_idx) - { - set_select_by("object"); - obj_id = m_volumes.volumes[volume_idx]->object_idx(); - vol_id = -1; - } - else - { - obj_id = object_idx; - vol_id = m_volumes.volumes[volume_idx]->volume_idx(); - } - } - else if (m_select_by == "object") - { - obj_id = m_volumes.volumes[volume_idx]->object_idx(); - vol_id = -1; - } - } - - post_event(ObjectSelectEvent(obj_id, vol_id)); - wxGetApp().obj_list()->select_current_volume(obj_id, vol_id); -} -#endif // !ENABLE_EXTENDED_SELECTION std::vector GLCanvas3D::_parse_colors(const std::vector& colors) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 779dce98b1..dc2f038172 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -82,21 +82,7 @@ public: void set_bottom(float bottom); }; -#if ENABLE_EXTENDED_SELECTION wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); -#else -struct ObjectSelectEvent; -wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, ObjectSelectEvent); -struct ObjectSelectEvent : public ArrayEvent -{ - ObjectSelectEvent(ptrdiff_t object_id, ptrdiff_t volume_id, wxObject *origin = nullptr) - : ArrayEvent(EVT_GLCANVAS_OBJECT_SELECT, {object_id, volume_id}, origin) - {} - - ptrdiff_t object_id() const { return data[0]; } - ptrdiff_t volume_id() const { return data[1]; } -}; -#endif // ENABLE_EXTENDED_SELECTION using Vec2dEvent = Event; template using Vec2dsEvent = ArrayEvent; @@ -106,30 +92,16 @@ template using Vec3dsEvent = ArrayEvent; wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); -#if !ENABLE_EXTENDED_SELECTION -wxDECLARE_EVENT(EVT_GLCANVAS_DOUBLE_CLICK, SimpleEvent); -#endif // !ENABLE_EXTENDED_SELECTION wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); -#if !ENABLE_EXTENDED_SELECTION -wxDECLARE_EVENT(EVT_GLCANVAS_ROTATE_OBJECT, Event); // data: -1 => rotate left, +1 => rotate right -wxDECLARE_EVENT(EVT_GLCANVAS_SCALE_UNIFORMLY, SimpleEvent); -#endif // !ENABLE_EXTENDED_SELECTION wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event); // data: +1 => increase, -1 => decrease wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); -#if !ENABLE_EXTENDED_SELECTION -wxDECLARE_EVENT(EVT_GIZMO_SCALE, Vec3dEvent); -wxDECLARE_EVENT(EVT_GIZMO_ROTATE, Vec3dEvent); -wxDECLARE_EVENT(EVT_GIZMO_FLATTEN, Vec3dEvent); -#endif // !ENABLE_EXTENDED_SELECTION - - class GLCanvas3D { struct GCodePreviewVolumeIndex @@ -356,15 +328,7 @@ class GLCanvas3D Point start_position_2D; Vec3d start_position_3D; -#if !ENABLE_EXTENDED_SELECTION - Vec3d volume_center_offset; - - bool move_with_shift; -#endif // !ENABLE_EXTENDED_SELECTION int move_volume_idx; -#if !ENABLE_EXTENDED_SELECTION - int gizmo_volume_idx; -#endif // !ENABLE_EXTENDED_SELECTION public: Drag(); @@ -386,7 +350,6 @@ class GLCanvas3D bool is_start_position_3D_defined() const; }; -#if ENABLE_EXTENDED_SELECTION public: class Selection { @@ -529,8 +492,6 @@ public: }; private: -#endif // ENABLE_EXTENDED_SELECTION - class Gizmos { static const float OverlayTexturesScale; @@ -564,20 +525,13 @@ private: bool is_enabled() const; void set_enabled(bool enable); -#if ENABLE_EXTENDED_SELECTION std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection); void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection); void update_on_off_state(const Selection& selection); -#else - void update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos); - void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos); -#endif // ENABLE_EXTENDED_SELECTION void reset_all_states(); void set_hover_id(int id); -#if ENABLE_EXTENDED_SELECTION void enable_grabber(EType type, unsigned int id, bool enable); -#endif // ENABLE_EXTENDED_SELECTION bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const; bool grabber_contains_mouse() const; @@ -591,19 +545,10 @@ private: bool is_running() const; bool is_dragging() const; -#if ENABLE_EXTENDED_SELECTION void start_dragging(const Selection& selection); -#else - void start_dragging(const BoundingBoxf3& box); -#endif // ENABLE_EXTENDED_SELECTION void stop_dragging(); -#if ENABLE_EXTENDED_SELECTION Vec3d get_displacement() const; -#else - Vec3d get_position() const; - void set_position(const Vec3d& position); -#endif // ENABLE_EXTENDED_SELECTION Vec3d get_scale() const; void set_scale(const Vec3d& scale); @@ -619,13 +564,8 @@ private: void clicked_on_object(const Vec2d& mouse_position); void delete_current_grabber(bool delete_all = false); -#if ENABLE_EXTENDED_SELECTION void render_current_gizmo(const Selection& selection) const; void render_current_gizmo_for_picking_pass(const Selection& selection) const; -#else - void render_current_gizmo(const BoundingBoxf3& box) const; - void render_current_gizmo_for_picking_pass(const BoundingBoxf3& box) const; -#endif // ENABLE_EXTENDED_SELECTION void render_overlay(const GLCanvas3D& canvas) const; @@ -633,11 +573,7 @@ private: void _reset(); void _render_overlay(const GLCanvas3D& canvas) const; -#if ENABLE_EXTENDED_SELECTION void _render_current_gizmo(const Selection& selection) const; -#else - void _render_current_gizmo(const BoundingBoxf3& box) const; -#endif // ENABLE_EXTENDED_SELECTION float _get_total_overlay_height() const; GLGizmoBase* _get_current() const; @@ -697,9 +633,7 @@ private: mutable GLToolbar m_toolbar; mutable GLVolumeCollection m_volumes; -#if ENABLE_EXTENDED_SELECTION Selection m_selection; -#endif // ENABLE_EXTENDED_SELECTION DynamicPrintConfig* m_config; Print* m_print; Model* m_model; @@ -718,21 +652,11 @@ private: bool m_shader_enabled; bool m_dynamic_background_enabled; bool m_multisample_allowed; -#if ENABLE_EXTENDED_SELECTION bool m_regenerate_volumes; -#endif // ENABLE_EXTENDED_SELECTION std::string m_color_by; -#if !ENABLE_EXTENDED_SELECTION - std::string m_select_by; - std::string m_drag_by; -#endif // !ENABLE_EXTENDED_SELECTION bool m_reload_delayed; -#if !ENABLE_EXTENDED_SELECTION - std::vector> m_objects_volumes_idxs; - std::vector m_objects_selections; -#endif // !ENABLE_EXTENDED_SELECTION GCodePreviewVolumeIndex m_gcode_preview_volume_index; @@ -759,27 +683,16 @@ public: unsigned int get_volumes_count() const; void reset_volumes(); -#if !ENABLE_EXTENDED_SELECTION - void deselect_volumes(); - void select_volume(unsigned int id); - void update_volumes_selection(const std::vector& selections); -#endif // !ENABLE_EXTENDED_SELECTION int check_volumes_outside_state(const DynamicPrintConfig* config) const; bool move_volume_up(unsigned int id); bool move_volume_down(unsigned int id); -#if !ENABLE_EXTENDED_SELECTION - void set_objects_selections(const std::vector& selections); -#endif // !ENABLE_EXTENDED_SELECTION - void set_config(DynamicPrintConfig* config); void set_print(Print* print); void set_model(Model* model); -#if ENABLE_EXTENDED_SELECTION const Selection& get_selection() const { return m_selection; } Selection& get_selection() { return m_selection; } -#endif // ENABLE_EXTENDED_SELECTION // Set the bed shape to a single closed 2D polygon(array of two element arrays), // triangulate the bed and store the triangles into m_bed.m_triangles, @@ -794,13 +707,6 @@ public: void set_cutting_plane(float z, const ExPolygons& polygons); void set_color_by(const std::string& value); -#if !ENABLE_EXTENDED_SELECTION - void set_select_by(const std::string& value); - void set_drag_by(const std::string& value); - - const std::string& get_select_by() const; - const std::string& get_drag_by() const; -#endif // !ENABLE_EXTENDED_SELECTION float get_camera_zoom() const; @@ -830,9 +736,7 @@ public: void zoom_to_bed(); void zoom_to_volumes(); #if ENABLE_MODIFIED_CAMERA_TARGET -#if ENABLE_EXTENDED_SELECTION void zoom_to_selection(); -#endif // ENABLE_EXTENDED_SELECTION #endif // ENABLE_MODIFIED_CAMERA_TARGET void select_view(const std::string& direction); void set_viewport_from_scene(const GLCanvas3D& other); @@ -853,9 +757,7 @@ public: int get_first_volume_id(int obj_idx) const; int get_in_object_volume_id(int scene_vol_idx) const; -#if ENABLE_EXTENDED_SELECTION void mirror_selection(Axis axis); -#endif // ENABLE_EXTENDED_SELECTION void reload_scene(bool force); @@ -893,9 +795,6 @@ private: void _resize(unsigned int w, unsigned int h); BoundingBoxf3 _max_bounding_box() const; -#if !ENABLE_EXTENDED_SELECTION - BoundingBoxf3 _selected_volumes_bounding_box() const; -#endif // !ENABLE_EXTENDED_SELECTION void _zoom_to_bounding_box(const BoundingBoxf3& bbox); float _get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const; @@ -909,9 +808,7 @@ private: void _render_bed(float theta) const; void _render_axes(bool depth_test) const; void _render_objects() const; -#if ENABLE_EXTENDED_SELECTION void _render_selection() const; -#endif // ENABLE_EXTENDED_SELECTION void _render_cutting_plane() const; void _render_warning_texture() const; void _render_legend_texture() const; @@ -924,9 +821,7 @@ private: void _render_camera_target() const; #endif // ENABLE_SHOW_CAMERA_TARGET -#if ENABLE_EXTENDED_SELECTION void _update_volumes_hover_state() const; -#endif // ENABLE_EXTENDED_SELECTION float _get_layers_editing_cursor_z_relative() const; void _perform_layer_editing_action(wxMouseEvent* evt = nullptr); @@ -944,11 +839,6 @@ private: void _start_timer(); void _stop_timer(); -#if !ENABLE_EXTENDED_SELECTION - int _get_first_selected_object_id() const; - int _get_first_selected_volume_id(int object_id) const; -#endif // !ENABLE_EXTENDED_SELECTION - // Create 3D thick extrusion lines for a skirt and brim. // Adds a new Slic3r::GUI::3DScene::Volume to volumes. void _load_print_toolpaths(); @@ -977,18 +867,11 @@ private: void _update_toolpath_volumes_outside_state(); void _show_warning_texture_if_needed(); -#if ENABLE_EXTENDED_SELECTION void _on_move(); void _on_rotate(); void _on_scale(); void _on_flatten(); void _on_mirror(); -#else - void _on_move(const std::vector& volume_idxs); -#endif // ENABLE_EXTENDED_SELECTION -#if !ENABLE_EXTENDED_SELECTION - void _on_select(int volume_idx, int object_idx); -#endif // !ENABLE_EXTENDED_SELECTION // generates the legend texture in dependence of the current shown view type void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors); diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 9a673b703e..55697e2be5 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -246,29 +246,6 @@ void GLCanvas3DManager::reset_volumes(wxGLCanvas* canvas) it->second->reset_volumes(); } -#if !ENABLE_EXTENDED_SELECTION -void GLCanvas3DManager::deselect_volumes(wxGLCanvas* canvas) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->deselect_volumes(); -} - -void GLCanvas3DManager::select_volume(wxGLCanvas* canvas, unsigned int id) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->select_volume(id); -} - -void GLCanvas3DManager::update_volumes_selection(wxGLCanvas* canvas, const std::vector& selections) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->update_volumes_selection(selections); -} -#endif // !ENABLE_EXTENDED_SELECTION - int GLCanvas3DManager::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -287,20 +264,11 @@ bool GLCanvas3DManager::move_volume_down(wxGLCanvas* canvas, unsigned int id) return (it != m_canvases.end()) ? it->second->move_volume_down(id) : false; } -#if ENABLE_EXTENDED_SELECTION GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas) { CanvasesMap::const_iterator it = _get_canvas(canvas); return (it != m_canvases.end()) ? it->second : nullptr; } -#else -void GLCanvas3DManager::set_objects_selections(wxGLCanvas* canvas, const std::vector& selections) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->set_objects_selections(selections); -} -#endif // ENABLE_EXTENDED_SELECTION void GLCanvas3DManager::set_config(wxGLCanvas* canvas, DynamicPrintConfig* config) { @@ -364,28 +332,6 @@ void GLCanvas3DManager::set_color_by(wxGLCanvas* canvas, const std::string& valu it->second->set_color_by(value); } -#if !ENABLE_EXTENDED_SELECTION -void GLCanvas3DManager::set_select_by(wxGLCanvas* canvas, const std::string& value) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->set_select_by(value); -} - -void GLCanvas3DManager::set_drag_by(wxGLCanvas* canvas, const std::string& value) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->set_drag_by(value); -} - -std::string GLCanvas3DManager::get_select_by(wxGLCanvas* canvas) const -{ - CanvasesMap::const_iterator it = _get_canvas(canvas); - return (it != m_canvases.end()) ? it->second->get_select_by() : ""; -} -#endif // !ENABLE_EXTENDED_SELECTION - bool GLCanvas3DManager::is_layers_editing_enabled(wxGLCanvas* canvas) const { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -596,14 +542,12 @@ int GLCanvas3DManager::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol return (it != m_canvases.end()) ? it->second->get_in_object_volume_id(scene_vol_idx) : -1; } -#if ENABLE_EXTENDED_SELECTION void GLCanvas3DManager::mirror_selection(wxGLCanvas* canvas, Axis axis) { CanvasesMap::iterator it = _get_canvas(canvas); if (it != m_canvases.end()) it->second->mirror_selection(axis); } -#endif // ENABLE_EXTENDED_SELECTION void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force) { diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 66d5fb1cd3..6ce805bdd8 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -87,20 +87,11 @@ public: unsigned int get_volumes_count(wxGLCanvas* canvas) const; void reset_volumes(wxGLCanvas* canvas); -#if !ENABLE_EXTENDED_SELECTION - void deselect_volumes(wxGLCanvas* canvas); - void select_volume(wxGLCanvas* canvas, unsigned int id); - void update_volumes_selection(wxGLCanvas* canvas, const std::vector& selections); -#endif // !ENABLE_EXTENDED_SELECTION int check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const; bool move_volume_up(wxGLCanvas* canvas, unsigned int id); bool move_volume_down(wxGLCanvas* canvas, unsigned int id); -#if ENABLE_EXTENDED_SELECTION GLCanvas3D* get_canvas(wxGLCanvas* canvas); -#else - void set_objects_selections(wxGLCanvas* canvas, const std::vector& selections); -#endif // ENABLE_EXTENDED_SELECTION void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config); void set_print(wxGLCanvas* canvas, Print* print); @@ -116,12 +107,6 @@ public: void set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons); void set_color_by(wxGLCanvas* canvas, const std::string& value); -#if !ENABLE_EXTENDED_SELECTION - void set_select_by(wxGLCanvas* canvas, const std::string& value); - void set_drag_by(wxGLCanvas* canvas, const std::string& value); - - std::string get_select_by(wxGLCanvas* canvas) const; -#endif // !ENABLE_EXTENDED_SELECTION bool is_layers_editing_enabled(wxGLCanvas* canvas) const; bool is_layers_editing_allowed(wxGLCanvas* canvas) const; @@ -163,9 +148,7 @@ public: int get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const; int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const; -#if ENABLE_EXTENDED_SELECTION void mirror_selection(wxGLCanvas* canvas, Axis axis); -#endif // ENABLE_EXTENDED_SELECTION void reload_scene(wxGLCanvas* canvas, bool force); diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 90c2e0bcef..6deedb0b37 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -4,9 +4,6 @@ #include "GUI.hpp" #include "../../libslic3r/Utils.hpp" -#if !ENABLE_EXTENDED_SELECTION -#include "../../slic3r/GUI/GLCanvas3D.hpp" -#endif // !ENABLE_EXTENDED_SELECTION #include #include "../../libslic3r/Geometry.hpp" @@ -26,91 +23,6 @@ static const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f namespace Slic3r { namespace GUI { -#if !ENABLE_EXTENDED_SELECTION -// returns the intersection of the given ray with the plane parallel to plane XY and passing through the given center -// coordinates are local to the plane -Vec3d intersection_on_plane_xy(const Linef3& ray, const Vec3d& center) -{ - Transform3d m = Transform3d::Identity(); - m.translate(-center); - Vec2d mouse_pos_2d = to_2d(transform(ray, m).intersect_plane(0.0)); - return Vec3d(mouse_pos_2d(0), mouse_pos_2d(1), 0.0); -} - -// returns the intersection of the given ray with the plane parallel to plane XZ and passing through the given center -// coordinates are local to the plane -Vec3d intersection_on_plane_xz(const Linef3& ray, const Vec3d& center) -{ - Transform3d m = Transform3d::Identity(); - m.rotate(Eigen::AngleAxisd(-0.5 * (double)PI, Vec3d::UnitX())); - m.translate(-center); - Vec2d mouse_pos_2d = to_2d(transform(ray, m).intersect_plane(0.0)); - return Vec3d(mouse_pos_2d(0), 0.0, mouse_pos_2d(1)); -} - -// returns the intersection of the given ray with the plane parallel to plane YZ and passing through the given center -// coordinates are local to the plane -Vec3d intersection_on_plane_yz(const Linef3& ray, const Vec3d& center) -{ - Transform3d m = Transform3d::Identity(); - m.rotate(Eigen::AngleAxisd(-0.5f * (double)PI, Vec3d::UnitY())); - m.translate(-center); - Vec2d mouse_pos_2d = to_2d(transform(ray, m).intersect_plane(0.0)); - - return Vec3d(0.0, mouse_pos_2d(1), -mouse_pos_2d(0)); -} - -// return an index: -// 0 for plane XY -// 1 for plane XZ -// 2 for plane YZ -// which indicates which plane is best suited for intersecting the given unit vector -// giving precedence to the plane with the given index -unsigned int select_best_plane(const Vec3d& unit_vector, unsigned int preferred_plane) -{ - unsigned int ret = preferred_plane; - - // 1st checks if the given vector is not parallel to the given preferred plane - double dot_to_normal = 0.0; - switch (ret) - { - case 0: // plane xy - { - dot_to_normal = std::abs(unit_vector.dot(Vec3d::UnitZ())); - break; - } - case 1: // plane xz - { - dot_to_normal = std::abs(unit_vector.dot(-Vec3d::UnitY())); - break; - } - case 2: // plane yz - { - dot_to_normal = std::abs(unit_vector.dot(Vec3d::UnitX())); - break; - } - default: - { - break; - } - } - - // if almost parallel, select the plane whose normal direction is closest to the given vector direction, - // otherwise return the given preferred plane index - if (dot_to_normal < 0.1) - { - typedef std::map ProjsMap; - ProjsMap projs_map; - projs_map.insert(ProjsMap::value_type(std::abs(unit_vector.dot(Vec3d::UnitZ())), 0)); // plane xy - projs_map.insert(ProjsMap::value_type(std::abs(unit_vector.dot(-Vec3d::UnitY())), 1)); // plane xz - projs_map.insert(ProjsMap::value_type(std::abs(unit_vector.dot(Vec3d::UnitX())), 2)); // plane yz - ret = projs_map.rbegin()->second; - } - - return ret; -} -#endif // !ENABLE_EXTENDED_SELECTION - const float GLGizmoBase::Grabber::SizeFactor = 0.025f; const float GLGizmoBase::Grabber::MinHalfSize = 1.5f; const float GLGizmoBase::Grabber::DraggingScaleFactor = 1.25f; @@ -262,11 +174,7 @@ void GLGizmoBase::disable_grabber(unsigned int id) on_disable_grabber(id); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoBase::start_dragging(const GLCanvas3D::Selection& selection) -#else -void GLGizmoBase::start_dragging(const BoundingBoxf3& box) -#endif // ENABLE_EXTENDED_SELECTION { m_dragging = true; @@ -275,11 +183,7 @@ void GLGizmoBase::start_dragging(const BoundingBoxf3& box) m_grabbers[i].dragging = (m_hover_id == i); } -#if ENABLE_EXTENDED_SELECTION on_start_dragging(selection); -#else - on_start_dragging(box); -#endif // ENABLE_EXTENDED_SELECTION } void GLGizmoBase::stop_dragging() @@ -385,15 +289,9 @@ bool GLGizmoRotate::on_init() return true; } -#if ENABLE_EXTENDED_SELECTION void GLGizmoRotate::on_start_dragging(const GLCanvas3D::Selection& selection) -#else -void GLGizmoRotate::on_start_dragging(const BoundingBoxf3& box) -#endif // ENABLE_EXTENDED_SELECTION { -#if ENABLE_EXTENDED_SELECTION const BoundingBoxf3& box = selection.get_bounding_box(); -#endif // ENABLE_EXTENDED_SELECTION m_center = box.center(); m_radius = Offset + box.radius(); m_snap_coarse_in_radius = m_radius / 3.0f; @@ -437,16 +335,11 @@ void GLGizmoRotate::on_update(const Linef3& mouse_ray, const Point* mouse_positi m_angle = theta; } -#if ENABLE_EXTENDED_SELECTION void GLGizmoRotate::on_render(const GLCanvas3D::Selection& selection) const -#else -void GLGizmoRotate::on_render(const BoundingBoxf3& box) const -#endif // ENABLE_EXTENDED_SELECTION { if (!m_grabbers[0].enabled) return; -#if ENABLE_EXTENDED_SELECTION const BoundingBoxf3& box = selection.get_bounding_box(); bool single_instance = selection.is_single_full_instance(); @@ -460,10 +353,6 @@ void GLGizmoRotate::on_render(const BoundingBoxf3& box) const if ((single_instance && (m_hover_id == 0)) || m_dragging) set_tooltip(axis + format((float)Geometry::rad2deg(m_angle), 4) + "\u00B0"); -#else - if (m_dragging) - set_tooltip(format(m_angle * 180.0f / (float)PI, 4)); -#endif // ENABLE_EXTENDED_SELECTION else { m_center = box.center(); @@ -501,22 +390,14 @@ void GLGizmoRotate::on_render(const BoundingBoxf3& box) const ::glPopMatrix(); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoRotate::on_render_for_picking(const GLCanvas3D::Selection& selection) const -#else -void GLGizmoRotate::on_render_for_picking(const BoundingBoxf3& box) const -#endif // ENABLE_EXTENDED_SELECTION { ::glDisable(GL_DEPTH_TEST); ::glPushMatrix(); transform_to_local(); -#if ENABLE_EXTENDED_SELECTION render_grabbers_for_picking(selection.get_bounding_box()); -#else - render_grabbers_for_picking(box); -#endif // ENABLE_EXTENDED_SELECTION ::glPopMatrix(); } @@ -733,19 +614,11 @@ std::string GLGizmoRotate3D::on_get_name() const return L("Rotate"); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoRotate3D::on_start_dragging(const GLCanvas3D::Selection& selection) { if ((0 <= m_hover_id) && (m_hover_id < 3)) m_gizmos[m_hover_id].start_dragging(selection); } -#else -void GLGizmoRotate3D::on_start_dragging(const BoundingBoxf3& box) -{ - if ((0 <= m_hover_id) && (m_hover_id < 3)) - m_gizmos[m_hover_id].start_dragging(box); -} -#endif // ENABLE_EXTENDED_SELECTION void GLGizmoRotate3D::on_stop_dragging() { @@ -753,7 +626,6 @@ void GLGizmoRotate3D::on_stop_dragging() m_gizmos[m_hover_id].stop_dragging(); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoRotate3D::on_render(const GLCanvas3D::Selection& selection) const { if ((m_hover_id == -1) || (m_hover_id == 0)) @@ -765,24 +637,8 @@ void GLGizmoRotate3D::on_render(const GLCanvas3D::Selection& selection) const if ((m_hover_id == -1) || (m_hover_id == 2)) m_gizmos[Z].render(selection); } -#else -void GLGizmoRotate3D::on_render(const BoundingBoxf3& box) const -{ - if ((m_hover_id == -1) || (m_hover_id == 0)) - m_gizmos[X].render(box); - - if ((m_hover_id == -1) || (m_hover_id == 1)) - m_gizmos[Y].render(box); - - if ((m_hover_id == -1) || (m_hover_id == 2)) - m_gizmos[Z].render(box); -} -#endif // ENABLE_EXTENDED_SELECTION const float GLGizmoScale3D::Offset = 5.0f; -#if !ENABLE_EXTENDED_SELECTION -const Vec3d GLGizmoScale3D::OffsetVec = (double)GLGizmoScale3D::Offset * Vec3d::Ones(); -#endif // !ENABLE_EXTENDED_SELECTION GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent) : GLGizmoBase(parent) @@ -830,20 +686,12 @@ std::string GLGizmoScale3D::on_get_name() const return L("Scale"); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoScale3D::on_start_dragging(const GLCanvas3D::Selection& selection) -#else -void GLGizmoScale3D::on_start_dragging(const BoundingBoxf3& box) -#endif // ENABLE_EXTENDED_SELECTION { if (m_hover_id != -1) { m_starting_drag_position = m_grabbers[m_hover_id].center; -#if ENABLE_EXTENDED_SELECTION m_starting_box = selection.get_bounding_box(); -#else - m_starting_box = BoundingBoxf3(box.min - OffsetVec, box.max + OffsetVec); -#endif // ENABLE_EXTENDED_SELECTION } } @@ -867,13 +715,8 @@ void GLGizmoScale3D::on_process_double_click() } #endif // ENABLE_GIZMOS_RESET -#if ENABLE_EXTENDED_SELECTION void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const -#else -void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const -#endif // ENABLE_EXTENDED_SELECTION { -#if ENABLE_EXTENDED_SELECTION bool single_instance = selection.is_single_full_instance(); Vec3f scale = single_instance ? 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_scaling_factor().cast() : 100.0f * m_scale.cast(); @@ -891,25 +734,9 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const tooltip += "Z: " + format(scale(2), 4) + "%"; set_tooltip(tooltip); } -#else - if (m_grabbers[0].dragging || m_grabbers[1].dragging) - set_tooltip("X: " + format(100.0f * m_scale(0), 4) + "%"); - else if (m_grabbers[2].dragging || m_grabbers[3].dragging) - set_tooltip("Y: " + format(100.0f * m_scale(1), 4) + "%"); - else if (m_grabbers[4].dragging || m_grabbers[5].dragging) - set_tooltip("Z: " + format(100.0f * m_scale(2), 4) + "%"); - else if (m_grabbers[6].dragging || m_grabbers[7].dragging || m_grabbers[8].dragging || m_grabbers[9].dragging) - { - std::string tooltip = "X: " + format(100.0f * m_scale(0), 4) + "%\n"; - tooltip += "Y: " + format(100.0f * m_scale(1), 4) + "%\n"; - tooltip += "Z: " + format(100.0f * m_scale(2), 4) + "%"; - set_tooltip(tooltip); - } -#endif // ENABLE_EXTENDED_SELECTION ::glEnable(GL_DEPTH_TEST); -#if ENABLE_EXTENDED_SELECTION BoundingBoxf3 box; Transform3d transform = Transform3d::Identity(); Vec3d angles = Vec3d::Zero(); @@ -942,74 +769,45 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const box = selection.get_bounding_box(); m_box = box; -#else - m_box = BoundingBoxf3(box.min - OffsetVec, box.max + OffsetVec); -#endif // ENABLE_EXTENDED_SELECTION const Vec3d& center = m_box.center(); -#if ENABLE_EXTENDED_SELECTION Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0); Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0); Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); -#endif // ENABLE_EXTENDED_SELECTION // x axis -#if ENABLE_EXTENDED_SELECTION m_grabbers[0].center = transform * Vec3d(m_box.min(0), center(1), center(2)) - offset_x; m_grabbers[1].center = transform * Vec3d(m_box.max(0), center(1), center(2)) + offset_x; -#else - m_grabbers[0].center = Vec3d(m_box.min(0), center(1), center(2)); - m_grabbers[1].center = Vec3d(m_box.max(0), center(1), center(2)); -#endif // ENABLE_EXTENDED_SELECTION ::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[0], 3 * sizeof(float)); // y axis -#if ENABLE_EXTENDED_SELECTION m_grabbers[2].center = transform * Vec3d(center(0), m_box.min(1), center(2)) - offset_y; m_grabbers[3].center = transform * Vec3d(center(0), m_box.max(1), center(2)) + offset_y; -#else - m_grabbers[2].center = Vec3d(center(0), m_box.min(1), center(2)); - m_grabbers[3].center = Vec3d(center(0), m_box.max(1), center(2)); -#endif // ENABLE_EXTENDED_SELECTION ::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[1], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[3].color, (const void*)&AXES_COLOR[1], 3 * sizeof(float)); // z axis -#if ENABLE_EXTENDED_SELECTION m_grabbers[4].center = transform * Vec3d(center(0), center(1), m_box.min(2)) - offset_z; m_grabbers[5].center = transform * Vec3d(center(0), center(1), m_box.max(2)) + offset_z; -#else - m_grabbers[4].center = Vec3d(center(0), center(1), m_box.min(2)); - m_grabbers[5].center = Vec3d(center(0), center(1), m_box.max(2)); -#endif // ENABLE_EXTENDED_SELECTION ::memcpy((void*)m_grabbers[4].color, (const void*)&AXES_COLOR[2], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[5].color, (const void*)&AXES_COLOR[2], 3 * sizeof(float)); // uniform -#if ENABLE_EXTENDED_SELECTION m_grabbers[6].center = transform * Vec3d(m_box.min(0), m_box.min(1), center(2)) - offset_x - offset_y; m_grabbers[7].center = transform * Vec3d(m_box.max(0), m_box.min(1), center(2)) + offset_x - offset_y; m_grabbers[8].center = transform * Vec3d(m_box.max(0), m_box.max(1), center(2)) + offset_x + offset_y; m_grabbers[9].center = transform * Vec3d(m_box.min(0), m_box.max(1), center(2)) - offset_x + offset_y; -#else - m_grabbers[6].center = Vec3d(m_box.min(0), m_box.min(1), center(2)); - m_grabbers[7].center = Vec3d(m_box.max(0), m_box.min(1), center(2)); - m_grabbers[8].center = Vec3d(m_box.max(0), m_box.max(1), center(2)); - m_grabbers[9].center = Vec3d(m_box.min(0), m_box.max(1), center(2)); -#endif // ENABLE_EXTENDED_SELECTION for (int i = 6; i < 10; ++i) { ::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 3 * sizeof(float)); } -#if ENABLE_EXTENDED_SELECTION // sets grabbers orientation for (int i = 0; i < 10; ++i) { m_grabbers[i].angles = angles; } -#endif // ENABLE_EXTENDED_SELECTION ::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f); @@ -1084,21 +882,12 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const } } -#if ENABLE_EXTENDED_SELECTION void GLGizmoScale3D::on_render_for_picking(const GLCanvas3D::Selection& selection) const { ::glDisable(GL_DEPTH_TEST); render_grabbers_for_picking(selection.get_bounding_box()); } -#else -void GLGizmoScale3D::on_render_for_picking(const BoundingBoxf3& box) const -{ - ::glDisable(GL_DEPTH_TEST); - - render_grabbers_for_picking(box); -} -#endif // ENABLE_EXTENDED_SELECTION void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2) const { @@ -1114,11 +903,7 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int void GLGizmoScale3D::do_scale_x(const Linef3& mouse_ray) { -#if ENABLE_EXTENDED_SELECTION double ratio = calc_ratio(mouse_ray); -#else - double ratio = calc_ratio(1, mouse_ray, m_starting_box.center()); -#endif // ENABLE_EXTENDED_SELECTION if (ratio > 0.0) m_scale(0) = m_starting_scale(0) * ratio; @@ -1126,11 +911,7 @@ void GLGizmoScale3D::do_scale_x(const Linef3& mouse_ray) void GLGizmoScale3D::do_scale_y(const Linef3& mouse_ray) { -#if ENABLE_EXTENDED_SELECTION double ratio = calc_ratio(mouse_ray); -#else - double ratio = calc_ratio(2, mouse_ray, m_starting_box.center()); -#endif // ENABLE_EXTENDED_SELECTION if (ratio > 0.0) m_scale(1) = m_starting_scale(1) * ratio; @@ -1138,11 +919,7 @@ void GLGizmoScale3D::do_scale_y(const Linef3& mouse_ray) void GLGizmoScale3D::do_scale_z(const Linef3& mouse_ray) { -#if ENABLE_EXTENDED_SELECTION double ratio = calc_ratio(mouse_ray); -#else - double ratio = calc_ratio(1, mouse_ray, m_starting_box.center()); -#endif // ENABLE_EXTENDED_SELECTION if (ratio > 0.0) m_scale(2) = m_starting_scale(2) * ratio; @@ -1150,19 +927,12 @@ void GLGizmoScale3D::do_scale_z(const Linef3& mouse_ray) void GLGizmoScale3D::do_scale_uniform(const Linef3& mouse_ray) { -#if ENABLE_EXTENDED_SELECTION double ratio = calc_ratio(mouse_ray); -#else - Vec3d center = m_starting_box.center(); - center(2) = m_box.min(2); - double ratio = calc_ratio(0, mouse_ray, center); -#endif // ENABLE_EXTENDED_SELECTION if (ratio > 0.0) m_scale = m_starting_scale * ratio; } -#if ENABLE_EXTENDED_SELECTION double GLGizmoScale3D::calc_ratio(const Linef3& mouse_ray) const { double ratio = 0.0; @@ -1189,53 +959,12 @@ double GLGizmoScale3D::calc_ratio(const Linef3& mouse_ray) const return ratio; } -#else -double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Vec3d& center) const -{ - double ratio = 0.0; - - Vec3d starting_vec = m_starting_drag_position - center; - double len_starting_vec = starting_vec.norm(); - if (len_starting_vec == 0.0) - return ratio; - - Vec3d starting_vec_dir = starting_vec.normalized(); - Vec3d mouse_dir = mouse_ray.unit_vector(); - - unsigned int plane_id = select_best_plane(mouse_dir, preferred_plane_id); - // ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length - switch (plane_id) - { - case 0: - { - ratio = starting_vec_dir.dot(intersection_on_plane_xy(mouse_ray, center)) / len_starting_vec; - break; - } - case 1: - { - ratio = starting_vec_dir.dot(intersection_on_plane_xz(mouse_ray, center)) / len_starting_vec; - break; - } - case 2: - { - ratio = starting_vec_dir.dot(intersection_on_plane_yz(mouse_ray, center)) / len_starting_vec; - break; - } - } - - return ratio; -} -#endif // ENABLE_EXTENDED_SELECTION const double GLGizmoMove3D::Offset = 10.0; GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent) : GLGizmoBase(parent) -#if ENABLE_EXTENDED_SELECTION , m_displacement(Vec3d::Zero()) -#else - , m_position(Vec3d::Zero()) -#endif // ENABLE_EXTENDED_SELECTION , m_starting_drag_position(Vec3d::Zero()) , m_starting_box_center(Vec3d::Zero()) , m_starting_box_bottom_center(Vec3d::Zero()) @@ -1271,18 +1000,12 @@ std::string GLGizmoMove3D::on_get_name() const return L("Move"); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoMove3D::on_start_dragging(const GLCanvas3D::Selection& selection) -#else -void GLGizmoMove3D::on_start_dragging(const BoundingBoxf3& box) -#endif // ENABLE_EXTENDED_SELECTION { if (m_hover_id != -1) { -#if ENABLE_EXTENDED_SELECTION m_displacement = Vec3d::Zero(); const BoundingBoxf3& box = selection.get_bounding_box(); -#endif // ENABLE_EXTENDED_SELECTION m_starting_drag_position = m_grabbers[m_hover_id].center; m_starting_box_center = box.center(); m_starting_box_bottom_center = box.center(); @@ -1290,39 +1013,23 @@ void GLGizmoMove3D::on_start_dragging(const BoundingBoxf3& box) } } -#if ENABLE_EXTENDED_SELECTION void GLGizmoMove3D::on_stop_dragging() { m_displacement = Vec3d::Zero(); } -#endif // ENABLE_EXTENDED_SELECTION void GLGizmoMove3D::on_update(const Linef3& mouse_ray, const Point* mouse_pos) { -#if ENABLE_EXTENDED_SELECTION if (m_hover_id == 0) m_displacement(0) = calc_projection(mouse_ray); else if (m_hover_id == 1) m_displacement(1) = calc_projection(mouse_ray); else if (m_hover_id == 2) m_displacement(2) = calc_projection(mouse_ray); -#else - if (m_hover_id == 0) - m_position(0) = 2.0 * m_starting_box_center(0) + calc_projection(X, 1, mouse_ray) - m_starting_drag_position(0); - else if (m_hover_id == 1) - m_position(1) = 2.0 * m_starting_box_center(1) + calc_projection(Y, 2, mouse_ray) - m_starting_drag_position(1); - else if (m_hover_id == 2) - m_position(2) = 2.0 * m_starting_box_bottom_center(2) + calc_projection(Z, 1, mouse_ray) - m_starting_drag_position(2); -#endif // ENABLE_EXTENDED_SELECTION } -#if ENABLE_EXTENDED_SELECTION void GLGizmoMove3D::on_render(const GLCanvas3D::Selection& selection) const -#else -void GLGizmoMove3D::on_render(const BoundingBoxf3& box) const -#endif // ENABLE_EXTENDED_SELECTION { -#if ENABLE_EXTENDED_SELECTION bool show_position = selection.is_single_full_instance(); const Vec3d& position = selection.get_bounding_box().center(); @@ -1332,20 +1039,10 @@ void GLGizmoMove3D::on_render(const BoundingBoxf3& box) const set_tooltip("Y: " + format(show_position ? position(1) : m_displacement(1), 2)); else if ((show_position && (m_hover_id == 2)) || m_grabbers[2].dragging) set_tooltip("Z: " + format(show_position ? position(2) : m_displacement(2), 2)); -#else - if (m_grabbers[0].dragging) - set_tooltip("X: " + format(m_position(0), 2)); - else if (m_grabbers[1].dragging) - set_tooltip("Y: " + format(m_position(1), 2)); - else if (m_grabbers[2].dragging) - set_tooltip("Z: " + format(m_position(2), 2)); -#endif // ENABLE_EXTENDED_SELECTION ::glEnable(GL_DEPTH_TEST); -#if ENABLE_EXTENDED_SELECTION const BoundingBoxf3& box = selection.get_bounding_box(); -#endif // ENABLE_EXTENDED_SELECTION const Vec3d& center = box.center(); // x axis @@ -1394,23 +1091,13 @@ void GLGizmoMove3D::on_render(const BoundingBoxf3& box) const } } -#if ENABLE_EXTENDED_SELECTION void GLGizmoMove3D::on_render_for_picking(const GLCanvas3D::Selection& selection) const { ::glDisable(GL_DEPTH_TEST); render_grabbers_for_picking(selection.get_bounding_box()); } -#else -void GLGizmoMove3D::on_render_for_picking(const BoundingBoxf3& box) const -{ - ::glDisable(GL_DEPTH_TEST); - render_grabbers_for_picking(box); -} -#endif // ENABLE_EXTENDED_SELECTION - -#if ENABLE_EXTENDED_SELECTION double GLGizmoMove3D::calc_projection(const Linef3& mouse_ray) const { double projection = 0.0; @@ -1433,43 +1120,6 @@ double GLGizmoMove3D::calc_projection(const Linef3& mouse_ray) const } return projection; } -#else -double GLGizmoMove3D::calc_projection(Axis axis, unsigned int preferred_plane_id, const Linef3& mouse_ray) const -{ - double projection = 0.0; - - Vec3d starting_vec = (axis == Z) ? m_starting_drag_position - m_starting_box_bottom_center : m_starting_drag_position - m_starting_box_center; - double len_starting_vec = starting_vec.norm(); - if (len_starting_vec == 0.0) - return projection; - - Vec3d starting_vec_dir = starting_vec.normalized(); - Vec3d mouse_dir = mouse_ray.unit_vector(); - - unsigned int plane_id = select_best_plane(mouse_dir, preferred_plane_id); - - switch (plane_id) - { - case 0: - { - projection = starting_vec_dir.dot(intersection_on_plane_xy(mouse_ray, (axis == Z) ? m_starting_box_bottom_center : m_starting_box_center)); - break; - } - case 1: - { - projection = starting_vec_dir.dot(intersection_on_plane_xz(mouse_ray, (axis == Z) ? m_starting_box_bottom_center : m_starting_box_center)); - break; - } - case 2: - { - projection = starting_vec_dir.dot(intersection_on_plane_yz(mouse_ray, (axis == Z) ? m_starting_box_bottom_center : m_starting_box_center)); - break; - } - } - - return projection; -} -#endif // ENABLE_EXTENDED_SELECTION GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent) : GLGizmoBase(parent) @@ -1502,42 +1152,24 @@ std::string GLGizmoFlatten::on_get_name() const return L("Flatten"); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoFlatten::on_start_dragging(const GLCanvas3D::Selection& selection) -#else -void GLGizmoFlatten::on_start_dragging(const BoundingBoxf3& box) -#endif // ENABLE_EXTENDED_SELECTION { if (m_hover_id != -1) { m_normal = m_planes[m_hover_id].normal; -#if ENABLE_EXTENDED_SELECTION m_starting_center = selection.get_bounding_box().center(); -#else - m_starting_center = box.center(); -#endif // ENABLE_EXTENDED_SELECTION } } -#if ENABLE_EXTENDED_SELECTION void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const -#else -void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const -#endif // ENABLE_EXTENDED_SELECTION { // the dragged_offset is a vector measuring where was the object moved // with the gizmo being on. This is reset in set_flattening_data and // does not work correctly when there are multiple copies. Vec3d dragged_offset(Vec3d::Zero()); -#if ENABLE_EXTENDED_SELECTION if (m_starting_center == Vec3d::Zero()) m_starting_center = selection.get_bounding_box().center(); dragged_offset = selection.get_bounding_box().center() - m_starting_center; -#else - if (m_starting_center == Vec3d::Zero()) - m_starting_center = box.center(); - dragged_offset = box.center() - m_starting_center; -#endif // ENABLE_EXTENDED_SELECTION ::glEnable(GL_BLEND); ::glEnable(GL_DEPTH_TEST); @@ -1549,7 +1181,6 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const else ::glColor4f(0.9f, 0.9f, 0.9f, 0.5f); -#if ENABLE_EXTENDED_SELECTION int instance_idx = selection.get_instance_idx(); if ((instance_idx != -1) && (m_model_object != nullptr)) { @@ -1565,30 +1196,13 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const ::glEnd(); ::glPopMatrix(); } -#else - for (const InstanceData& inst : m_instances) { - Transform3d m = inst.matrix; - m.pretranslate(dragged_offset); - ::glPushMatrix(); - ::glMultMatrixd(m.data()); - ::glBegin(GL_POLYGON); - for (const Vec3d& vertex : m_planes[i].vertices) - ::glVertex3dv(vertex.data()); - ::glEnd(); - ::glPopMatrix(); - } -#endif // ENABLE_EXTENDED_SELECTION } ::glEnable(GL_CULL_FACE); ::glDisable(GL_BLEND); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selection) const -#else -void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const -#endif // ENABLE_EXTENDED_SELECTION { ::glEnable(GL_DEPTH_TEST); ::glDisable(GL_CULL_FACE); @@ -1596,7 +1210,6 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const for (unsigned int i = 0; i < m_planes.size(); ++i) { ::glColor3f(1.0f, 1.0f, picking_color_component(i)); -#if ENABLE_EXTENDED_SELECTION int instance_idx = selection.get_instance_idx(); if ((instance_idx != -1) && (m_model_object != nullptr)) { @@ -1610,17 +1223,6 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const ::glEnd(); ::glPopMatrix(); } -#else - for (const InstanceData& inst : m_instances) { - ::glPushMatrix(); - ::glMultMatrixd(inst.matrix.data()); - ::glBegin(GL_POLYGON); - for (const Vec3d& vertex : m_planes[i].vertices) - ::glVertex3dv(vertex.data()); - ::glEnd(); - ::glPopMatrix(); - } -#endif // ENABLE_EXTENDED_SELECTION } ::glEnable(GL_CULL_FACE); @@ -1631,15 +1233,6 @@ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) m_starting_center = Vec3d::Zero(); m_model_object = model_object; -#if !ENABLE_EXTENDED_SELECTION - // ...and save the updated positions of the object instances: - if (m_model_object && !m_model_object->instances.empty()) { - m_instances.clear(); - for (const auto* instance : m_model_object->instances) - m_instances.emplace_back(instance->world_matrix()); - } -#endif // !ENABLE_EXTENDED_SELECTION - if (is_plane_update_necessary()) update_planes(); } @@ -1890,11 +1483,7 @@ void GLGizmoSlaSupports::set_model_object_ptr(ModelObject* model_object) update_mesh(); } -#if ENABLE_EXTENDED_SELECTION void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const -#else -void GLGizmoSlaSupports::on_render(const BoundingBoxf3& box) const -#endif { ::glEnable(GL_BLEND); ::glEnable(GL_DEPTH_TEST); @@ -1903,15 +1492,9 @@ void GLGizmoSlaSupports::on_render(const BoundingBoxf3& box) const // with the gizmo being on. This is reset in set_flattening_data and // does not work correctly when there are multiple copies. -#if ENABLE_EXTENDED_SELECTION if (m_starting_center == Vec3d::Zero()) m_starting_center = selection.get_bounding_box().center(); Vec3d dragged_offset = selection.get_bounding_box().center() - m_starting_center; -#else - if (m_starting_center == Vec3d::Zero()) - m_starting_center = box.center(); - Vec3d dragged_offset(box.center() - m_starting_center); -#endif // ENABLE_EXTENDED_SELECTION for (auto& g : m_grabbers) { g.color[0] = 1.f; @@ -1929,11 +1512,7 @@ void GLGizmoSlaSupports::on_render(const BoundingBoxf3& box) const } -#if ENABLE_EXTENDED_SELECTION void GLGizmoSlaSupports::on_render_for_picking(const GLCanvas3D::Selection& selection) const -#else -void GLGizmoSlaSupports::on_render_for_picking(const BoundingBoxf3& box) const -#endif { ::glEnable(GL_DEPTH_TEST); for (unsigned int i=0; i m_planes; -#if !ENABLE_EXTENDED_SELECTION - struct InstanceData - { - Transform3d matrix; - InstanceData(const Transform3d& matrix) : matrix(matrix) {} - }; - std::vector m_instances; -#endif // !ENABLE_EXTENDED_SELECTION mutable Vec3d m_starting_center; const ModelObject* m_model_object = nullptr; @@ -463,22 +361,11 @@ public: protected: virtual bool on_init(); virtual std::string on_get_name() const; -#if ENABLE_EXTENDED_SELECTION virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return selection.is_single_full_instance(); } -#endif // ENABLE_EXTENDED_SELECTION -#if ENABLE_EXTENDED_SELECTION virtual void on_start_dragging(const GLCanvas3D::Selection& selection); -#else - virtual void on_start_dragging(const BoundingBoxf3& box); -#endif // ENABLE_EXTENDED_SELECTION virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos) {} -#if ENABLE_EXTENDED_SELECTION virtual void on_render(const GLCanvas3D::Selection& selection) const; virtual void on_render_for_picking(const GLCanvas3D::Selection& selection) const; -#else - virtual void on_render(const BoundingBoxf3& box) const; - virtual void on_render_for_picking(const BoundingBoxf3& box) const; -#endif // ENABLE_EXTENDED_SELECTION virtual void on_set_state() { if (m_state == On && is_plane_update_necessary()) @@ -515,13 +402,8 @@ public: private: bool on_init(); void on_update(const Linef3& mouse_ray, const Point* mouse_pos); -#if ENABLE_EXTENDED_SELECTION virtual void on_render(const GLCanvas3D::Selection& selection) const; virtual void on_render_for_picking(const GLCanvas3D::Selection& selection) const; -#else - virtual void on_render(const BoundingBoxf3& box) const; - virtual void on_render_for_picking(const BoundingBoxf3& box) const; -#endif // ENABLE_EXTENDED_SELECTION void render_grabbers(bool picking = false) const; void render_tooltip_texture() const; diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 265fc20426..26ca4a4dca 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -25,13 +25,7 @@ wxDEFINE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT_VOLUMES, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_CUT, SimpleEvent); -#if !ENABLE_EXTENDED_SELECTION -wxDEFINE_EVENT(EVT_GLTOOLBAR_SETTINGS, SimpleEvent); -#endif // !ENABLE_EXTENDED_SELECTION wxDEFINE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); -#if !ENABLE_EXTENDED_SELECTION -wxDEFINE_EVENT(EVT_GLTOOLBAR_SELECTBYPARTS, SimpleEvent); -#endif // !ENABLE_EXTENDED_SELECTION GLToolbarItem::Data::Data() diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 9f3853530c..6669bc9664 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -25,13 +25,7 @@ wxDECLARE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_SPLIT_VOLUMES, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_CUT, SimpleEvent); -#if !ENABLE_EXTENDED_SELECTION -wxDECLARE_EVENT(EVT_GLTOOLBAR_SETTINGS, SimpleEvent); -#endif // !ENABLE_EXTENDED_SELECTION wxDECLARE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); -#if !ENABLE_EXTENDED_SELECTION -wxDECLARE_EVENT(EVT_GLTOOLBAR_SELECTBYPARTS, SimpleEvent); -#endif // !ENABLE_EXTENDED_SELECTION class GLToolbarItem { diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 243da51367..1c3150ce50 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -960,10 +960,8 @@ void ObjectList::split(const bool split_part) m_parts_changed = true; parts_changed(m_selected_object_id); -#if ENABLE_EXTENDED_SELECTION // restores selection _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection().add_object(m_selected_object_id); -#endif // ENABLE_EXTENDED_SELECTION } bool ObjectList::get_volume_by_item(const bool split_part, const wxDataViewItem& item, ModelVolume*& volume) @@ -1071,11 +1069,7 @@ void ObjectList::part_selection_changed() m_selected_object_id = obj_idx; -#if ENABLE_EXTENDED_SELECTION wxGetApp().obj_manipul()->update_settings_value(_3DScene::get_canvas(wxGetApp().canvas3D())->get_selection()); -#else - wxGetApp().obj_manipul()->update_values(); -#endif // ENABLE_EXTENDED_SELECTION } void ObjectList::update_manipulation_sizer(const bool is_simple_mode) @@ -1094,9 +1088,6 @@ void ObjectList::add_object_to_list(size_t obj_idx) auto model_object = (*m_objects)[obj_idx]; wxString item_name = model_object->name; auto item = m_objects_model->Add(item_name); -#if !ENABLE_EXTENDED_SELECTION - /*Select*/select_item(item); -#endif // !ENABLE_EXTENDED_SELECTION // Add error icon if detected auto-repaire auto stats = model_object->volumes[0]->mesh.stl.stats; @@ -1224,7 +1215,6 @@ bool ObjectList::multiple_selection() const void ObjectList::update_selections() { -#if ENABLE_EXTENDED_SELECTION auto& selection = _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection(); wxDataViewItemArray sels; @@ -1234,13 +1224,10 @@ void ObjectList::update_selections() sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); } select_items(sels); - -#endif // ENABLE_EXTENDED_SELECTION } void ObjectList::update_selections_on_canvas() { -#if ENABLE_EXTENDED_SELECTION auto& selection = _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection(); const int sel_cnt = GetSelectedItemsCount(); @@ -1288,8 +1275,6 @@ void ObjectList::update_selections_on_canvas() add_to_selection(item, selection, false); _3DScene::render(wxGetApp().canvas3D()); - -#endif // ENABLE_EXTENDED_SELECTION } void ObjectList::select_item(const wxDataViewItem& item) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 78031cf306..8cb7944f6b 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -266,7 +266,6 @@ void ObjectManipulation::update_settings_list() parent->GetParent()->Layout(); } -#if ENABLE_EXTENDED_SELECTION void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection) { if (selection.is_single_full_object()) @@ -344,7 +343,6 @@ void ObjectManipulation::reset_scale_value() m_og->set_value("scale_y", 100); m_og->set_value("scale_z", 100); } -#endif // ENABLE_EXTENDED_SELECTION void ObjectManipulation::update_values() { diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 13b9290a0a..4192041cd5 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -6,9 +6,7 @@ #include #include "Preset.hpp" -#if ENABLE_EXTENDED_SELECTION #include "GLCanvas3D.hpp" -#endif // ENABLE_EXTENDED_SELECTION class wxBoxSizer; @@ -16,7 +14,6 @@ namespace Slic3r { namespace GUI { class ConfigOptionsGroup; - class OG_Settings { protected: @@ -47,13 +44,11 @@ public: int ol_selection(); void update_settings_list(); -#if ENABLE_EXTENDED_SELECTION void update_settings_value(const GLCanvas3D::Selection& selection); void reset_settings_value(); void reset_position_value(); void reset_rotation_value(); void reset_scale_value(); -#endif // ENABLE_EXTENDED_SELECTION void update_values(); // update position values displacements or "gizmos" diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 1c21a27ca4..828e439529 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -754,18 +754,6 @@ std::vector& Sidebar::combos_filament() return p->combos_filament; } -#if !ENABLE_EXTENDED_SELECTION -// Plater::Object - -struct PlaterObject -{ - std::string name; - bool selected; - - PlaterObject(std::string name) : name(std::move(name)), selected(false) {} -}; -#endif // !ENABLE_EXTENDED_SELECTION - // Plater::DropTarget class PlaterDropTarget : public wxFileDropTarget @@ -817,9 +805,6 @@ struct Plater::priv Slic3r::Print print; Slic3r::Model model; Slic3r::GCodePreviewData gcode_preview_data; -#if !ENABLE_EXTENDED_SELECTION - std::vector objects; -#endif // !ENABLE_EXTENDED_SELECTION // GUI elements wxNotebook *notebook; @@ -835,9 +820,6 @@ struct Plater::priv priv(Plater *q, MainFrame *main_frame); -#if !ENABLE_EXTENDED_SELECTION - std::vector collect_selections(); -#endif // !ENABLE_EXTENDED_SELECTION void update(bool force_autocenter = false); void select_view(const std::string& direction); void update_ui_from_settings(); @@ -849,30 +831,15 @@ struct Plater::priv std::vector load_model_objects(const ModelObjectPtrs &model_objects); std::unique_ptr get_export_file(GUI::FileType file_type); -#if ENABLE_EXTENDED_SELECTION const GLCanvas3D::Selection& get_selection() const; GLCanvas3D::Selection& get_selection(); int get_selected_object_idx() const; -#else - void select_object(optional obj_idx); - void select_object_from_cpp(); - optional selected_object() const; -#endif // ENABLE_EXTENDED_SELECTION void selection_changed(); void object_list_changed(); -#if !ENABLE_EXTENDED_SELECTION - void select_view(); -#endif // !ENABLE_EXTENDED_SELECTION void remove(size_t obj_idx); void reset(); -#if !ENABLE_EXTENDED_SELECTION - void rotate(); -#endif // !ENABLE_EXTENDED_SELECTION void mirror(Axis axis); -#if !ENABLE_EXTENDED_SELECTION - void scale(); -#endif // !ENABLE_EXTENDED_SELECTION void arrange(); void split_object(); void split_volume(); @@ -896,25 +863,12 @@ struct Plater::priv void on_action_split_objects(SimpleEvent&); void on_action_split_volumes(SimpleEvent&); void on_action_cut(SimpleEvent&); -#if !ENABLE_EXTENDED_SELECTION - void on_action_settings(SimpleEvent&); -#endif // !ENABLE_EXTENDED_SELECTION void on_action_layersediting(SimpleEvent&); -#if !ENABLE_EXTENDED_SELECTION - void on_action_selectbyparts(SimpleEvent&); -#endif // !ENABLE_EXTENDED_SELECTION -#if ENABLE_EXTENDED_SELECTION void on_object_select(SimpleEvent&); -#else - void on_object_select(ObjectSelectEvent&); -#endif // ENABLE_EXTENDED_SELECTION void on_viewport_changed(SimpleEvent&); void on_right_click(Vec2dEvent&); void on_model_update(SimpleEvent&); -#if !ENABLE_EXTENDED_SELECTION - void on_scale_uniformly(SimpleEvent&); -#endif // !ENABLE_EXTENDED_SELECTION void on_wipetower_moved(Vec3dEvent&); void on_enable_action_buttons(Event&); void on_update_geometry(Vec3dsEvent<2>&); @@ -922,7 +876,6 @@ struct Plater::priv private: bool init_object_menu(); -#if ENABLE_EXTENDED_SELECTION bool can_delete_object() const; bool can_increase_instances() const; bool can_decrease_instances() const; @@ -933,7 +886,6 @@ private: bool can_delete_all() const; bool can_arrange() const; bool can_mirror() const; -#endif // ENABLE_EXTENDED_SELECTION }; const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase); @@ -976,10 +928,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : _3DScene::enable_picking(canvas3D, true); _3DScene::enable_moving(canvas3D, true); // XXX: more config from 3D.pm -#if !ENABLE_EXTENDED_SELECTION - _3DScene::set_select_by(canvas3D, "object"); - _3DScene::set_drag_by(canvas3D, "instance"); -#endif // !ENABLE_EXTENDED_SELECTION _3DScene::set_model(canvas3D, &model); _3DScene::set_print(canvas3D, &print); _3DScene::set_config(canvas3D, config); @@ -1017,17 +965,10 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : canvas3D->Bind(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, &priv::on_schedule_background_process, this); canvas3D->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this); canvas3D->Bind(EVT_GLCANVAS_VIEWPORT_CHANGED, &priv::on_viewport_changed, this); -#if !ENABLE_EXTENDED_SELECTION - canvas3D->Bind(EVT_GLCANVAS_DOUBLE_CLICK, [](SimpleEvent&) {}); // XXX: remove? -#endif // !ENABLE_EXTENDED_SELECTION canvas3D->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this); canvas3D->Bind(EVT_GLCANVAS_MODEL_UPDATE, &priv::on_model_update, this); canvas3D->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [q](SimpleEvent&) { q->remove_selected(); }); canvas3D->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); }); -#if !ENABLE_EXTENDED_SELECTION - canvas3D->Bind(EVT_GLCANVAS_ROTATE_OBJECT, [this](Event &evt) { /*TODO: call rotate */ }); - canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, [this](SimpleEvent&) { this->scale(); }); -#endif // !ENABLE_EXTENDED_SELECTION canvas3D->Bind(EVT_GLCANVAS_INCREASE_INSTANCES, [q](Event &evt) { evt.data == 1 ? q->increase_instances() : q->decrease_instances(); }); canvas3D->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); }); canvas3D->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this); @@ -1043,13 +984,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : canvas3D->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this); canvas3D->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this); canvas3D->Bind(EVT_GLTOOLBAR_CUT, &priv::on_action_cut, this); -#if !ENABLE_EXTENDED_SELECTION - canvas3D->Bind(EVT_GLTOOLBAR_SETTINGS, &priv::on_action_settings, this); -#endif // !ENABLE_EXTENDED_SELECTION canvas3D->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this); -#if !ENABLE_EXTENDED_SELECTION - canvas3D->Bind(EVT_GLTOOLBAR_SELECTBYPARTS, &priv::on_action_selectbyparts, this); -#endif // !ENABLE_EXTENDED_SELECTION // Preview events: preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_VIEWPORT_CHANGED, &priv::on_viewport_changed, this); @@ -1064,17 +999,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : q->Layout(); } -#if !ENABLE_EXTENDED_SELECTION -std::vector Plater::priv::collect_selections() -{ - std::vector res; - for (const auto &obj : objects) { - res.push_back(obj.selected); - } - return res; -} -#endif // !ENABLE_EXTENDED_SELECTION - void Plater::priv::update(bool force_autocenter) { wxWindowUpdateLocker freeze_guard(q); @@ -1086,10 +1010,6 @@ void Plater::priv::update(bool force_autocenter) model.center_instances_around_point(bed_center); } -#if !ENABLE_EXTENDED_SELECTION - const auto selections = collect_selections(); - _3DScene::set_objects_selections(canvas3D, selections); -#endif // !ENABLE_EXTENDED_SELECTION _3DScene::reload_scene(canvas3D, false); preview->reset_gcode_preview_data(); preview->reload_print(); @@ -1261,19 +1181,12 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode bool need_arrange = false; bool scaled_down = false; std::vector obj_idxs; -#if ENABLE_EXTENDED_SELECTION unsigned int obj_count = model.objects.size(); -#endif // ENABLE_EXTENDED_SELECTION for (ModelObject *model_object : model_objects) { auto *object = model.add_object(*model_object); std::string object_name = object->name.empty() ? fs::path(object->input_file).filename().string() : object->name; -#if ENABLE_EXTENDED_SELECTION obj_idxs.push_back(obj_count++); -#else - objects.emplace_back(std::move(object_name)); - obj_idxs.push_back(objects.size() - 1); -#endif // ENABLE_EXTENDED_SELECTION if (model_object->instances.empty()) { // if object has no defined position(s) we need to rearrange everything after loading @@ -1385,7 +1298,6 @@ std::unique_ptr Plater::priv::get_export_file(GUI::FileType return dlg; } -#if ENABLE_EXTENDED_SELECTION const GLCanvas3D::Selection& Plater::priv::get_selection() const { return _3DScene::get_canvas(canvas3D)->get_selection(); @@ -1401,43 +1313,9 @@ int Plater::priv::get_selected_object_idx() const int idx = get_selection().get_object_idx(); return ((0 <= idx) && (idx < 1000)) ? idx : -1; } -#else -void Plater::priv::select_object(optional obj_idx) -{ - for (auto &obj : objects) { - obj.selected = false; - } - - if (obj_idx) { - objects[*obj_idx].selected = true; - } - - selection_changed(); -} - -void Plater::priv::select_object_from_cpp() -{ - // TODO -} - -optional Plater::priv::selected_object() const -{ - for (size_t i = 0; i < objects.size(); i++) { - if (objects[i].selected) { return i; } - } - - return boost::none; -} -#endif // ENABLE_EXTENDED_SELECTION void Plater::priv::selection_changed() { -#if !ENABLE_EXTENDED_SELECTION - const auto obj_idx = selected_object(); - const bool have_sel = !!obj_idx; -#endif // !ENABLE_EXTENDED_SELECTION - -#if ENABLE_EXTENDED_SELECTION _3DScene::enable_toolbar_item(canvas3D, "delete", can_delete_object()); _3DScene::enable_toolbar_item(canvas3D, "more", can_increase_instances()); _3DScene::enable_toolbar_item(canvas3D, "fewer", can_decrease_instances()); @@ -1447,45 +1325,13 @@ void Plater::priv::selection_changed() _3DScene::enable_toolbar_item(canvas3D, "layersediting", layers_height_allowed()); // forces a frame render to update the view (to avoid a missed update if, for example, the context menu appears) _3DScene::render(canvas3D); -#else - _3DScene::enable_toolbar_item(canvas3D, "fewer", have_sel); - _3DScene::enable_toolbar_item(canvas3D, "splitobjects", have_sel); - _3DScene::enable_toolbar_item(canvas3D, "splitvolumes", have_sel); - _3DScene::enable_toolbar_item(canvas3D, "cut", have_sel); - _3DScene::enable_toolbar_item(canvas3D, "settings", have_sel); - _3DScene::enable_toolbar_item(canvas3D, "layersediting", have_sel && config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D)); -#endif // ENABLE_EXTENDED_SELECTION -#if ENABLE_EXTENDED_SELECTION int obj_idx = get_selected_object_idx(); bool have_sel = (obj_idx != -1); -#else - bool can_select_by_parts = false; - - if (have_sel) { - const auto *model_object = model.objects[*obj_idx]; - // XXX: ? - can_select_by_parts = *obj_idx < 1000 && model_object->volumes.size() > 1; - _3DScene::enable_toolbar_item(canvas3D, "fewer", model_object->instances.size() > 1); - } - - if (can_select_by_parts) { - // first disable to let the item in the toolbar to switch to the unpressed state // XXX: ? - _3DScene::enable_toolbar_item(canvas3D, "selectbyparts", false); - _3DScene::enable_toolbar_item(canvas3D, "selectbyparts", true); - } else { - _3DScene::enable_toolbar_item(canvas3D, "selectbyparts", false); - _3DScene::set_select_by(canvas3D, "object"); - } -#endif // ENABLE_EXTENDED_SELECTION wxWindowUpdateLocker freeze_guard(sidebar); if (have_sel) { -#if ENABLE_EXTENDED_SELECTION const ModelObject* model_object = model.objects[obj_idx]; -#else - const auto *model_object = model.objects[*obj_idx]; -#endif // ENABLE_EXTENDED_SELECTION // FIXME print_info runs model fixing in two rounds, it is very slow, it should not be performed here! // # $model_object->print_info; @@ -1531,33 +1377,16 @@ void Plater::priv::selection_changed() void Plater::priv::object_list_changed() { // Enable/disable buttons depending on whether there are any objects on the platter. -#if ENABLE_EXTENDED_SELECTION _3DScene::enable_toolbar_item(canvas3D, "deleteall", can_delete_all()); _3DScene::enable_toolbar_item(canvas3D, "arrange", can_arrange()); -#else - const bool have_objects = !objects.empty(); - _3DScene::enable_toolbar_item(canvas3D, "deleteall", have_objects); - _3DScene::enable_toolbar_item(canvas3D, "arrange", have_objects); -#endif // ENABLE_EXTENDED_SELECTION const bool export_in_progress = this->background_process.is_export_scheduled(); // || ! send_gcode_file.empty()); // XXX: is this right? const bool model_fits = _3DScene::check_volumes_outside_state(canvas3D, config) == ModelInstance::PVS_Inside; -#if ENABLE_EXTENDED_SELECTION sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits); -#else - sidebar->enable_buttons(have_objects && !export_in_progress && model_fits); -#endif // ENABLE_EXTENDED_SELECTION } -#if !ENABLE_EXTENDED_SELECTION -void Plater::priv::select_view() -{ - // TODO -} -#endif // !ENABLE_EXTENDED_SELECTION - void Plater::priv::remove(size_t obj_idx) { // Prevent toolpaths preview from rendering while we modify the Print object @@ -1566,19 +1395,12 @@ void Plater::priv::remove(size_t obj_idx) if (_3DScene::is_layers_editing_enabled(canvas3D)) _3DScene::enable_layers_editing(canvas3D, false); -#if !ENABLE_EXTENDED_SELECTION - objects.erase(objects.begin() + obj_idx); -#endif // !ENABLE_EXTENDED_SELECTION model.delete_object(obj_idx); // print.delete_object(obj_idx); // Delete object from Sidebar list sidebar->obj_list()->delete_object_from_list(obj_idx); object_list_changed(); - -#if !ENABLE_EXTENDED_SELECTION - select_object(boost::none); -#endif // !ENABLE_EXTENDED_SELECTION update(); } @@ -1590,43 +1412,20 @@ void Plater::priv::reset() if (_3DScene::is_layers_editing_enabled(canvas3D)) _3DScene::enable_layers_editing(canvas3D, false); -#if !ENABLE_EXTENDED_SELECTION - objects.clear(); -#endif // !ENABLE_EXTENDED_SELECTION model.clear_objects(); // print.clear_objects(); // Delete all objects from list on c++ side sidebar->obj_list()->delete_all_objects_from_list(); object_list_changed(); - -#if !ENABLE_EXTENDED_SELECTION - select_object(boost::none); -#endif // !ENABLE_EXTENDED_SELECTION update(); } -#if !ENABLE_EXTENDED_SELECTION -void Plater::priv::rotate() -{ - // TODO -} -#endif // !ENABLE_EXTENDED_SELECTION - void Plater::priv::mirror(Axis axis) { -#if ENABLE_EXTENDED_SELECTION _3DScene::mirror_selection(canvas3D, axis); -#endif // ENABLE_EXTENDED_SELECTION } -#if !ENABLE_EXTENDED_SELECTION -void Plater::priv::scale() -{ - // TODO -} -#endif // !ENABLE_EXTENDED_SELECTION - void Plater::priv::arrange() { main_frame->app_controller()->arrange_model(); @@ -1639,7 +1438,6 @@ void Plater::priv::arrange() void Plater::priv::split_object() { -#if ENABLE_EXTENDED_SELECTION int obj_idx = get_selected_object_idx(); if (obj_idx == -1) return; @@ -1683,7 +1481,6 @@ void Plater::priv::split_object() get_selection().add_object((unsigned int)idx, false); } } -#endif // ENABLE_EXTENDED_SELECTION } void Plater::priv::split_volume() @@ -1723,11 +1520,9 @@ void Plater::priv::async_apply_config() this->preview->reload_print(); // We also need to reload 3D scene because of the wipe tower preview box if (this->config->opt_bool("wipe_tower")) { -#if !ENABLE_EXTENDED_SELECTION - std::vector selections = this->collect_selections(); - Slic3r::_3DScene::set_objects_selections(this->canvas3D, selections); - Slic3r::_3DScene::reload_scene(this->canvas3D, 1); -#endif /* !ENABLE_EXTENDED_SELECTION */ +// std::vector selections = this->collect_selections(); +// Slic3r::_3DScene::set_objects_selections(this->canvas3D, selections); +// Slic3r::_3DScene::reload_scene(this->canvas3D, 1); } } if (invalidated != Print::APPLY_STATUS_UNCHANGED && this->get_config("background_processing") == "1" && @@ -1801,9 +1596,6 @@ void Plater::priv::on_notebook_changed(wxBookCtrlEvent&) const auto current_id = notebook->GetCurrentPage()->GetId(); if (current_id == canvas3D->GetId()) { if (_3DScene::is_reload_delayed(canvas3D)) { -#if !ENABLE_EXTENDED_SELECTION - _3DScene::set_objects_selections(canvas3D, collect_selections()); -#endif // !ENABLE_EXTENDED_SELECTION _3DScene::reload_scene(canvas3D, true); } // sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) @@ -1865,12 +1657,10 @@ void Plater::priv::on_update_print_preview(wxCommandEvent &) if (this->preview != nullptr) this->preview->reload_print(); // in case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth: -#if !ENABLE_EXTENDED_SELECTION - auto selections = collect_selections(); - _3DScene::set_objects_selections(canvas3D, selections); - if (canvas3D) - _3DScene::reload_scene(canvas3D, true); -#endif // !ENABLE_EXTENDED_SELECTION +// auto selections = collect_selections(); +// _3DScene::set_objects_selections(canvas3D, selections); +// if (canvas3D) +// _3DScene::reload_scene(canvas3D, true); } void Plater::priv::on_process_completed(wxCommandEvent &evt) @@ -1942,13 +1732,6 @@ void Plater::priv::on_action_cut(SimpleEvent&) // TODO } -#if !ENABLE_EXTENDED_SELECTION -void Plater::priv::on_action_settings(SimpleEvent&) -{ - // TODO -} -#endif // !ENABLE_EXTENDED_SELECTION - void Plater::priv::on_action_layersediting(SimpleEvent&) { bool enable = !_3DScene::is_layers_editing_enabled(canvas3D); @@ -1957,31 +1740,11 @@ void Plater::priv::on_action_layersediting(SimpleEvent&) _3DScene::enable_toolbar_item(canvas3D, "layersediting", false); } -#if !ENABLE_EXTENDED_SELECTION -void Plater::priv::on_action_selectbyparts(SimpleEvent&) -{ - // TODO -} -#endif // !ENABLE_EXTENDED_SELECTION - -#if ENABLE_EXTENDED_SELECTION void Plater::priv::on_object_select(SimpleEvent& evt) { selection_changed(); wxGetApp().obj_list()->update_selections(); } -#else -void Plater::priv::on_object_select(ObjectSelectEvent &evt) -{ - const auto obj_idx = evt.object_id(); - const auto vol_idx = evt.volume_id(); - - if (obj_idx >= 0 && obj_idx < 1000 && vol_idx == -1) { - // Ignore the special objects (the wipe tower proxy and such). - select_object(obj_idx); -} -} -#endif // ENABLE_EXTENDED_SELECTION void Plater::priv::on_viewport_changed(SimpleEvent& evt) { @@ -1994,16 +1757,12 @@ void Plater::priv::on_viewport_changed(SimpleEvent& evt) void Plater::priv::on_right_click(Vec2dEvent& evt) { -#if ENABLE_EXTENDED_SELECTION int obj_idx = get_selected_object_idx(); if (obj_idx == -1) return; if (q != nullptr) q->PopupMenu(&object_menu, (int)evt.data.x(), (int)evt.data.y()); -#else - // TODO -#endif // ENABLE_EXTENDED_SELECTION } void Plater::priv::on_model_update(SimpleEvent&) @@ -2011,42 +1770,6 @@ void Plater::priv::on_model_update(SimpleEvent&) // TODO } -#if !ENABLE_EXTENDED_SELECTION -void Plater::priv::on_scale_uniformly(SimpleEvent&) -{ -// my ($scale) = @_; - -// my ($obj_idx, $object) = $self->selected_object; - const auto obj_idx = selected_object(); - if (! obj_idx) { return; } -// return if !defined $obj_idx; - -// my $model_object = $self->{model}->objects->[$obj_idx]; -// my $model_instance = $model_object->instances->[0]; - -// my $variation = $scale / $model_instance->scaling_factor; -// #FIXME Scale the layer height profile? -// foreach my $range (@{ $model_object->layer_height_ranges }) { -// $range->[0] *= $variation; -// $range->[1] *= $variation; -// } -// $_->set_scaling_factor($scale) for @{ $model_object->instances }; - -// # Set object scale on c++ side -// # Slic3r::GUI::set_object_scale($obj_idx, $model_object->instances->[0]->scaling_factor * 100); - -// # $object->transform_thumbnail($self->{model}, $obj_idx); - -// #update print and start background processing -// $self->{print}->add_model_object($model_object, $obj_idx); - -// $self->selection_changed(1); # refresh info (size, volume etc.) -// $self->update; - - this->schedule_background_process(); -} -#endif // !ENABLE_EXTENDED_SELECTION - void Plater::priv::on_wipetower_moved(Vec3dEvent &evt) { DynamicPrintConfig cfg; @@ -2102,7 +1825,6 @@ bool Plater::priv::init_object_menu() wxMenuItem* item_split = append_submenu(&object_menu, split_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object")), "shape_ungroup.png"); -#if ENABLE_EXTENDED_SELECTION // ui updates needs to be binded to the parent panel if (q != nullptr) { @@ -2115,12 +1837,10 @@ bool Plater::priv::init_object_menu() q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split_to_objects()); }, item_split_objects->GetId()); q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split_to_volumes()); }, item_split_volumes->GetId()); } -#endif // ENABLE_EXTENDED_SELECTION return true; } -#if ENABLE_EXTENDED_SELECTION bool Plater::priv::can_delete_object() const { int obj_idx = get_selected_object_idx(); @@ -2177,7 +1897,6 @@ bool Plater::priv::can_mirror() const { return get_selection().is_from_single_instance(); } -#endif // ENABLE_EXTENDED_SELECTION // Plater / Public @@ -2218,51 +1937,28 @@ void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } void Plater::remove_selected() { -#if ENABLE_EXTENDED_SELECTION int obj_idx = p->get_selected_object_idx(); if (obj_idx != -1) remove((size_t)obj_idx); -#else - const auto selected = p->selected_object(); - if (selected) { - remove(*selected); - } -#endif // ENABLE_EXTENDED_SELECTION } void Plater::increase_instances(size_t num) { -#if ENABLE_EXTENDED_SELECTION int obj_idx = p->get_selected_object_idx(); if (obj_idx == -1) return; ModelObject* model_object = p->model.objects[obj_idx]; ModelInstance* model_instance = model_object->instances.back(); -#else - const auto obj_idx = p->selected_object(); - if (! obj_idx) { return; } - - auto *model_object = p->model.objects[*obj_idx]; - auto *model_instance = model_object->instances[model_object->instances.size() - 1]; -#endif // ENABLE_EXTENDED_SELECTION float offset = 10.0; for (size_t i = 0; i < num; i++, offset += 10.0) { Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0); model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation()); -#if ENABLE_EXTENDED_SELECTION // p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); -#else -// p->print.get_object(*obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); -#endif // ENABLE_EXTENDED_SELECTION } -#if ENABLE_EXTENDED_SELECTION sidebar().obj_list()->increase_object_instances(obj_idx, num); -#else - sidebar().obj_list()->increase_object_instances(*obj_idx, num); -#endif // ENABLE_EXTENDED_SELECTION if (p->get_config("autocenter") == "1") { p->arrange(); @@ -2270,9 +1966,7 @@ void Plater::increase_instances(size_t num) p->update(); } -#if ENABLE_EXTENDED_SELECTION p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1); -#endif // ENABLE_EXTENDED_SELECTION p->selection_changed(); @@ -2281,47 +1975,26 @@ void Plater::increase_instances(size_t num) void Plater::decrease_instances(size_t num) { -#if ENABLE_EXTENDED_SELECTION int obj_idx = p->get_selected_object_idx(); if (obj_idx == -1) return; ModelObject* model_object = p->model.objects[obj_idx]; -#else - const auto obj_idx = p->selected_object(); - if (! obj_idx) { return; } - - auto *model_object = p->model.objects[*obj_idx]; -#endif // ENABLE_EXTENDED_SELECTION if (model_object->instances.size() > num) { for (size_t i = 0; i < num; i++) { model_object->delete_last_instance(); -#if ENABLE_EXTENDED_SELECTION // p->print.get_object(obj_idx)->delete_last_copy(); -#else -// p->print.get_object(*obj_idx)->delete_last_copy(); -#endif // ENABLE_EXTENDED_SELECTION } -#if ENABLE_EXTENDED_SELECTION sidebar().obj_list()->decrease_object_instances(obj_idx, num); -#else - sidebar().obj_list()->decrease_object_instances(*obj_idx, num); -#endif // ENABLE_EXTENDED_SELECTION } else { -#if ENABLE_EXTENDED_SELECTION remove(obj_idx); -#else - remove(*obj_idx); -#endif // ENABLE_EXTENDED_SELECTION } p->update(); -#if ENABLE_EXTENDED_SELECTION if (!model_object->instances.empty()) p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1); -#endif // ENABLE_EXTENDED_SELECTION p->selection_changed(); this->p->schedule_background_process(); @@ -2329,18 +2002,11 @@ void Plater::decrease_instances(size_t num) void Plater::set_number_of_copies(/*size_t num*/) { -#if ENABLE_EXTENDED_SELECTION int obj_idx = p->get_selected_object_idx(); if (obj_idx == -1) return; ModelObject* model_object = p->model.objects[obj_idx]; -#else - const auto obj_idx = p->selected_object(); - if (! obj_idx) { return; } - - auto *model_object = p->model.objects[*obj_idx]; -#endif // ENABLE_EXTENDED_SELECTION const auto num = wxGetNumberFromUser( " ", _("Enter the number of copies:"), _("Copies of the selected object"), model_object->instances.size(), 0, 1000, this ); @@ -2356,13 +2022,8 @@ void Plater::set_number_of_copies(/*size_t num*/) void Plater::export_gcode(fs::path output_path) { -#if ENABLE_EXTENDED_SELECTION if (p->model.objects.empty()) return; -#else - if (p->objects.empty()) - return; -#endif // ENABLE_EXTENDED_SELECTION if (this->p->background_process.is_export_scheduled()) { GUI::show_error(this, _(L("Another export job is currently running."))); @@ -2414,11 +2075,7 @@ void Plater::export_gcode(fs::path output_path) void Plater::export_stl() { -#if ENABLE_EXTENDED_SELECTION if (p->model.objects.empty()) { return; } -#else - if (p->objects.empty()) { return; } -#endif // ENABLE_EXTENDED_SELECTION auto dialog = p->get_export_file(FT_STL); if (! dialog) { return; } @@ -2433,11 +2090,7 @@ void Plater::export_stl() void Plater::export_amf() { -#if ENABLE_EXTENDED_SELECTION if (p->model.objects.empty()) { return; } -#else - if (p->objects.empty()) { return; } -#endif // ENABLE_EXTENDED_SELECTION auto dialog = p->get_export_file(FT_AMF); if (! dialog) { return; } @@ -2456,11 +2109,7 @@ void Plater::export_amf() void Plater::export_3mf() { -#if ENABLE_EXTENDED_SELECTION if (p->model.objects.empty()) { return; } -#else - if (p->objects.empty()) { return; } -#endif // ENABLE_EXTENDED_SELECTION auto dialog = p->get_export_file(FT_3MF); if (! dialog) { return; } @@ -2600,11 +2249,6 @@ void Plater::changed_object(int obj_idx) // update print if (list->is_parts_changed() || list->is_part_settings_changed()) { this->p->schedule_background_process(); -#if !ENABLE_EXTENDED_SELECTION - if (p->canvas3D) _3DScene::reload_scene(p->canvas3D, true); - auto selections = p->collect_selections(); - _3DScene::set_objects_selections(p->canvas3D, selections); -#endif // !ENABLE_EXTENDED_SELECTION #if !ENABLE_MODIFIED_CAMERA_TARGET _3DScene::zoom_to_volumes(p->canvas3D); #endif // !ENABLE_MODIFIED_CAMERA_TARGET From 42d3db9ab17c067e6bc518ce96d77e5ea9e9bb97 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 1 Nov 2018 10:25:08 +0100 Subject: [PATCH 11/12] Fixed typo in Transformation::set_rotation() --- src/libslic3r/Geometry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 83ebb3b32e..9f23f73f23 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1272,7 +1272,7 @@ void Transformation::set_rotation(Axis axis, double rotation) { rotation = angle_to_0_2PI(rotation); - if (m_rotation(axis) = rotation) + if (m_rotation(axis) != rotation) { m_rotation(axis) = rotation; m_dirty = true; From 26d373a2e2ecf7c46a2f01a5424a339f2ab0c31a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 1 Nov 2018 13:42:07 +0100 Subject: [PATCH 12/12] Added extended functionality to Geometry::Transformation class --- src/libslic3r/Format/3mf.cpp | 9 +++++++ src/libslic3r/Geometry.cpp | 48 ++++++++++++++++++++++++++++++++++ src/libslic3r/Geometry.hpp | 7 ++++- src/libslic3r/Technologies.hpp | 8 +++--- 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 5dd6f8a8e1..103af9a031 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1329,6 +1329,14 @@ namespace Slic3r { void _3MF_Importer::_apply_transform(ModelInstance& instance, const Transform3d& transform) { +#if ENABLE_MODELVOLUME_TRANSFORM + Slic3r::Geometry::Transformation t(transform); + // invalid scale value, return + if (!t.get_scaling_factor().all()) + return; + + instance.set_transformation(t); +#else // translation Vec3d offset = transform.matrix().block(0, 3, 3, 1); @@ -1363,6 +1371,7 @@ namespace Slic3r { instance.set_scaling_factor(scale); instance.set_rotation(rotation); instance.set_mirror(mirror); +#endif // ENABLE_MODELVOLUME_TRANSFORM } bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 9f23f73f23..256f48e85c 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1245,6 +1245,11 @@ Transformation::Transformation() { } +Transformation::Transformation(const Transform3d& transform) +{ + set_from_transform(transform); +} + void Transformation::set_offset(const Vec3d& offset) { set_offset(X, offset(0)); @@ -1317,6 +1322,45 @@ void Transformation::set_mirror(Axis axis, double mirror) } } +void Transformation::set_from_transform(const Transform3d& transform) +{ + // offset + set_offset(transform.matrix().block(0, 3, 3, 1)); + + Eigen::Matrix m3x3 = transform.matrix().block(0, 0, 3, 3); + + // mirror + // it is impossible to reconstruct the original mirroring factors from a matrix, + // we can only detect if the matrix contains a left handed reference system + // in which case we reorient it back to right handed by mirroring the x axis + Vec3d mirror = Vec3d::Ones(); + if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) + { + mirror(0) = -1.0; + // remove mirror + m3x3.col(0) *= -1.0; + } + set_mirror(mirror); + + // scale + set_scaling_factor(Vec3d(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm())); + + // remove scale + m3x3.col(0).normalize(); + m3x3.col(1).normalize(); + m3x3.col(2).normalize(); + + // rotation + set_rotation(extract_euler_angles(m3x3)); + + // forces matrix recalculation matrix + m_matrix = get_matrix(); + +// // debug check +// if (!m_matrix.isApprox(transform)) +// std::cout << "something went wrong in extracting data from matrix" << std::endl; +} + const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const { if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) @@ -1335,6 +1379,10 @@ const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rot return m_matrix; } +Transformation Transformation::operator * (const Transformation& other) const +{ + return Transformation(get_matrix() * other.get_matrix()); +} #endif // ENABLE_MODELVOLUME_TRANSFORM } } diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index fd3560b7be..c21c3946d3 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -217,13 +217,14 @@ class Transformation Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point Vec3d m_scaling_factor; // Scaling factors along the three axes Vec3d m_mirror; // Mirroring along the three axes - mutable Transform3d m_matrix; + mutable Transform3d m_matrix; mutable Flags m_flags; mutable bool m_dirty; public: Transformation(); + explicit Transformation(const Transform3d& transform); const Vec3d& get_offset() const { return m_offset; } double get_offset(Axis axis) const { return m_offset(axis); } @@ -249,7 +250,11 @@ public: void set_mirror(const Vec3d& mirror); void set_mirror(Axis axis, double mirror); + void set_from_transform(const Transform3d& transform); + const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const; + + Transformation operator * (const Transformation& other) const; }; #endif // ENABLE_MODELVOLUME_TRANSFORM diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 73d342f08c..8193661462 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -1,16 +1,16 @@ #ifndef _technologies_h_ #define _technologies_h_ -//============== +//============ // debug techs -//============== +//============ // Shows camera target in the 3D scene #define ENABLE_SHOW_CAMERA_TARGET 1 -//============== +//============= // 1.42.0 techs -//============== +//============= #define ENABLE_1_42_0 1 // Add double click on gizmo grabbers to reset transformation components to their default value