Config.pm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. package Slic3r::Config;
  2. use strict;
  3. use warnings;
  4. use utf8;
  5. use constant PI => 4 * atan2(1, 1);
  6. # cemetery of old config settings
  7. our @Ignore = qw(duplicate_x duplicate_y multiply_x multiply_y);
  8. our $Options = {
  9. # miscellaneous options
  10. 'notes' => {
  11. label => 'Configuration notes',
  12. cli => 'notes=s',
  13. type => 's',
  14. multiline => 1,
  15. width => 220,
  16. height => 130,
  17. serialize => sub { join '\n', split /\R/, $_[0] },
  18. deserialize => sub { join "\n", split /\\n/, $_[0] },
  19. },
  20. 'threads' => {
  21. label => 'Threads (more speed, more memory usage)',
  22. cli => 'threads|j=i',
  23. type => 'i',
  24. },
  25. # output options
  26. 'output_filename_format' => {
  27. label => 'Output filename format',
  28. cli => 'output-filename-format=s',
  29. type => 's',
  30. },
  31. # printer options
  32. 'nozzle_diameter' => {
  33. label => 'Nozzle diameter (mm)',
  34. cli => 'nozzle-diameter=f',
  35. type => 'f',
  36. important => 1,
  37. },
  38. 'print_center' => {
  39. label => 'Print center (mm)',
  40. cli => 'print-center=s',
  41. type => 'point',
  42. serialize => sub { join ',', @{$_[0]} },
  43. deserialize => sub { [ split /,/, $_[0] ] },
  44. },
  45. 'gcode_flavor' => {
  46. label => 'G-code flavor',
  47. cli => 'gcode-flavor=s',
  48. type => 'select',
  49. values => [qw(reprap teacup makerbot mach3 no-extrusion)],
  50. labels => ['RepRap (Marlin/Sprinter)', 'Teacup', 'MakerBot', 'Mach3/EMC', 'No extrusion'],
  51. },
  52. 'use_relative_e_distances' => {
  53. label => 'Use relative E distances',
  54. cli => 'use-relative-e-distances',
  55. type => 'bool',
  56. },
  57. 'extrusion_axis' => {
  58. label => 'Extrusion axis',
  59. cli => 'extrusion-axis=s',
  60. type => 's',
  61. },
  62. 'z_offset' => {
  63. label => 'Z offset (mm)',
  64. cli => 'z-offset=f',
  65. type => 'f',
  66. },
  67. 'gcode_arcs' => {
  68. label => 'Use native G-code arcs',
  69. cli => 'gcode-arcs',
  70. type => 'bool',
  71. },
  72. 'g0' => {
  73. label => 'Use G0 for travel moves',
  74. cli => 'g0',
  75. type => 'bool',
  76. },
  77. 'gcode_comments' => {
  78. label => 'Verbose G-code',
  79. cli => 'gcode-comments',
  80. type => 'bool',
  81. },
  82. # filament options
  83. 'filament_diameter' => {
  84. label => 'Diameter (mm)',
  85. cli => 'filament-diameter=f',
  86. type => 'f',
  87. important => 1,
  88. },
  89. 'extrusion_multiplier' => {
  90. label => 'Extrusion multiplier',
  91. cli => 'extrusion-multiplier=f',
  92. type => 'f',
  93. aliases => [qw(filament_packing_density)],
  94. },
  95. 'first_layer_temperature' => {
  96. label => 'First layer temperature (°C)',
  97. cli => 'first-layer-temperature=i',
  98. type => 'i',
  99. },
  100. 'first_layer_bed_temperature' => {
  101. label => 'First layer bed temperature (°C)',
  102. cli => 'first-layer-bed-temperature=i',
  103. type => 'i',
  104. },
  105. 'temperature' => {
  106. label => 'Temperature (°C)',
  107. cli => 'temperature=i',
  108. type => 'i',
  109. important => 1,
  110. },
  111. 'bed_temperature' => {
  112. label => 'Bed Temperature (°C)',
  113. cli => 'bed-temperature=i',
  114. type => 'i',
  115. },
  116. # speed options
  117. 'travel_speed' => {
  118. label => 'Travel (mm/s)',
  119. cli => 'travel-speed=f',
  120. type => 'f',
  121. aliases => [qw(travel_feed_rate)],
  122. },
  123. 'perimeter_speed' => {
  124. label => 'Perimeters (mm/s)',
  125. cli => 'perimeter-speed=f',
  126. type => 'f',
  127. aliases => [qw(perimeter_feed_rate)],
  128. },
  129. 'small_perimeter_speed' => {
  130. label => 'Small perimeters (mm/s)',
  131. cli => 'small-perimeter-speed=f',
  132. type => 'f',
  133. },
  134. 'infill_speed' => {
  135. label => 'Infill (mm/s)',
  136. cli => 'infill-speed=f',
  137. type => 'f',
  138. aliases => [qw(print_feed_rate infill_feed_rate)],
  139. },
  140. 'solid_infill_speed' => {
  141. label => 'Solid infill (mm/s)',
  142. cli => 'solid-infill-speed=f',
  143. type => 'f',
  144. aliases => [qw(solid_infill_feed_rate)],
  145. },
  146. 'bridge_speed' => {
  147. label => 'Bridges (mm/s)',
  148. cli => 'bridge-speed=f',
  149. type => 'f',
  150. aliases => [qw(bridge_feed_rate)],
  151. },
  152. 'first_layer_speed' => {
  153. label => 'First layer speed (mm/s or %)',
  154. cli => 'first-layer-speed=s',
  155. type => 'f',
  156. },
  157. # acceleration options
  158. 'acceleration' => {
  159. label => 'Enable acceleration control',
  160. cli => 'acceleration',
  161. type => 'bool',
  162. },
  163. 'perimeter_acceleration' => {
  164. label => 'Perimeters (mm/s²)',
  165. cli => 'perimeter-acceleration',
  166. type => 'f',
  167. },
  168. 'infill_acceleration' => {
  169. label => 'Infill (mm/s²)',
  170. cli => 'infill-acceleration',
  171. type => 'f',
  172. },
  173. # accuracy options
  174. 'layer_height' => {
  175. label => 'Layer height (mm)',
  176. cli => 'layer-height=f',
  177. type => 'f',
  178. },
  179. 'first_layer_height' => {
  180. label => 'First layer height (mm or %)',
  181. cli => 'first-layer-height=s',
  182. type => 'f',
  183. },
  184. 'infill_every_layers' => {
  185. label => 'Infill every N layers',
  186. cli => 'infill-every-layers=i',
  187. type => 'i',
  188. },
  189. # flow options
  190. 'extrusion_width' => {
  191. label => 'Extrusion width (mm or %; leave zero to calculate automatically)',
  192. cli => 'extrusion-width=s',
  193. type => 'f',
  194. },
  195. 'first_layer_extrusion_width' => {
  196. label => 'First layer extrusion width (mm or % or 0 for default)',
  197. cli => 'first-layer-extrusion-width=s',
  198. type => 'f',
  199. },
  200. 'perimeters_extrusion_width' => {
  201. label => 'Perimeters extrusion width (mm or % or 0 for default)',
  202. cli => 'perimeters-extrusion-width=s',
  203. type => 'f',
  204. },
  205. 'infill_extrusion_width' => {
  206. label => 'Infill extrusion width (mm or % or 0 for default)',
  207. cli => 'infill-extrusion-width=s',
  208. type => 'f',
  209. },
  210. 'bridge_flow_ratio' => {
  211. label => 'Bridge flow ratio',
  212. cli => 'bridge-flow-ratio=f',
  213. type => 'f',
  214. },
  215. # print options
  216. 'perimeters' => {
  217. label => 'Perimeters (minimum)',
  218. cli => 'perimeters=i',
  219. type => 'i',
  220. aliases => [qw(perimeter_offsets)],
  221. },
  222. 'solid_layers' => {
  223. label => 'Solid layers',
  224. cli => 'solid-layers=i',
  225. type => 'i',
  226. },
  227. 'fill_pattern' => {
  228. label => 'Fill pattern',
  229. cli => 'fill-pattern=s',
  230. type => 'select',
  231. values => [qw(rectilinear line concentric honeycomb hilbertcurve archimedeanchords octagramspiral)],
  232. labels => [qw(rectilinear line concentric honeycomb), 'hilbertcurve (slow)', 'archimedeanchords (slow)', 'octagramspiral (slow)'],
  233. },
  234. 'solid_fill_pattern' => {
  235. label => 'Solid fill pattern',
  236. cli => 'solid-fill-pattern=s',
  237. type => 'select',
  238. values => [qw(rectilinear concentric hilbertcurve archimedeanchords octagramspiral)],
  239. labels => [qw(rectilinear concentric), 'hilbertcurve (slow)', 'archimedeanchords (slow)', 'octagramspiral (slow)'],
  240. },
  241. 'fill_density' => {
  242. label => 'Fill density',
  243. cli => 'fill-density=f',
  244. type => 'f',
  245. },
  246. 'fill_angle' => {
  247. label => 'Fill angle (°)',
  248. cli => 'fill-angle=i',
  249. type => 'i',
  250. },
  251. 'randomize_start' => {
  252. label => 'Randomize starting points',
  253. cli => 'randomize-start',
  254. type => 'bool',
  255. },
  256. 'support_material' => {
  257. label => 'Generate support material',
  258. cli => 'support-material',
  259. type => 'bool',
  260. },
  261. 'support_material_tool' => {
  262. label => 'Tool used to extrude support material',
  263. cli => 'support-material-tool=i',
  264. type => 'select',
  265. values => [0,1],
  266. labels => [qw(Primary Secondary)],
  267. },
  268. 'start_gcode' => {
  269. label => 'Start G-code',
  270. cli => 'start-gcode=s',
  271. type => 's',
  272. multiline => 1,
  273. width => 350,
  274. height => 120,
  275. serialize => sub { join '\n', split /\R+/, $_[0] },
  276. deserialize => sub { join "\n", split /\\n/, $_[0] },
  277. },
  278. 'end_gcode' => {
  279. label => 'End G-code',
  280. cli => 'end-gcode=s',
  281. type => 's',
  282. multiline => 1,
  283. width => 350,
  284. height => 120,
  285. serialize => sub { join '\n', split /\R+/, $_[0] },
  286. deserialize => sub { join "\n", split /\\n/, $_[0] },
  287. },
  288. 'layer_gcode' => {
  289. label => 'Layer change G-code',
  290. cli => 'layer-gcode=s',
  291. type => 's',
  292. multiline => 1,
  293. width => 350,
  294. height => 50,
  295. serialize => sub { join '\n', split /\R+/, $_[0] },
  296. deserialize => sub { join "\n", split /\\n/, $_[0] },
  297. },
  298. 'post_process' => {
  299. label => 'Post-processing scripts',
  300. cli => 'post-process=s@',
  301. type => 's@',
  302. multiline => 1,
  303. width => 350,
  304. height => 60,
  305. serialize => sub { join '; ', @{$_[0]} },
  306. deserialize => sub { [ split /\s*;\s*/, $_[0] ] },
  307. },
  308. # retraction options
  309. 'retract_length' => {
  310. label => 'Length (mm)',
  311. cli => 'retract-length=f',
  312. type => 'f',
  313. },
  314. 'retract_speed' => {
  315. label => 'Speed (mm/s)',
  316. cli => 'retract-speed=f',
  317. type => 'i',
  318. },
  319. 'retract_restart_extra' => {
  320. label => 'Extra length on restart (mm)',
  321. cli => 'retract-restart-extra=f',
  322. type => 'f',
  323. },
  324. 'retract_before_travel' => {
  325. label => 'Minimum travel after retraction (mm)',
  326. cli => 'retract-before-travel=f',
  327. type => 'f',
  328. },
  329. 'retract_lift' => {
  330. label => 'Lift Z (mm)',
  331. cli => 'retract-lift=f',
  332. type => 'f',
  333. },
  334. # cooling options
  335. 'cooling' => {
  336. label => 'Enable cooling',
  337. cli => 'cooling',
  338. type => 'bool',
  339. },
  340. 'min_fan_speed' => {
  341. label => 'Min fan speed (%)',
  342. cli => 'min-fan-speed=i',
  343. type => 'i',
  344. },
  345. 'max_fan_speed' => {
  346. label => 'Max fan speed (%)',
  347. cli => 'max-fan-speed=i',
  348. type => 'i',
  349. },
  350. 'bridge_fan_speed' => {
  351. label => 'Bridge fan speed (%)',
  352. cli => 'bridge-fan-speed=i',
  353. type => 'i',
  354. },
  355. 'fan_below_layer_time' => {
  356. label => 'Enable fan if layer print time is below (approximate seconds)',
  357. cli => 'fan-below-layer-time=i',
  358. type => 'i',
  359. },
  360. 'slowdown_below_layer_time' => {
  361. label => 'Slow down if layer print time is below (approximate seconds)',
  362. cli => 'slowdown-below-layer-time=i',
  363. type => 'i',
  364. },
  365. 'min_print_speed' => {
  366. label => 'Min print speed (mm/s)',
  367. cli => 'min-print-speed=f',
  368. type => 'i',
  369. },
  370. 'disable_fan_first_layers' => {
  371. label => 'Disable fan for the first N layers',
  372. cli => 'disable-fan-first-layers=i',
  373. type => 'i',
  374. },
  375. 'fan_always_on' => {
  376. label => 'Keep fan always on',
  377. cli => 'fan-always-on',
  378. type => 'bool',
  379. },
  380. # skirt options
  381. 'skirts' => {
  382. label => 'Loops',
  383. cli => 'skirts=i',
  384. type => 'i',
  385. },
  386. 'skirt_distance' => {
  387. label => 'Distance from object (mm)',
  388. cli => 'skirt-distance=f',
  389. type => 'i',
  390. },
  391. 'skirt_height' => {
  392. label => 'Skirt height (layers)',
  393. cli => 'skirt-height=i',
  394. type => 'i',
  395. },
  396. # transform options
  397. 'scale' => {
  398. label => 'Scale',
  399. cli => 'scale=f',
  400. type => 'f',
  401. },
  402. 'rotate' => {
  403. label => 'Rotate (°)',
  404. cli => 'rotate=i',
  405. type => 'i',
  406. },
  407. 'duplicate_mode' => {
  408. label => 'Duplicate',
  409. gui_only => 1,
  410. type => 'select',
  411. values => [qw(no autoarrange grid)],
  412. labels => ['No', 'Autoarrange', 'Grid'],
  413. },
  414. 'duplicate' => {
  415. label => 'Copies (autoarrange)',
  416. cli => 'duplicate=i',
  417. type => 'i',
  418. },
  419. 'bed_size' => {
  420. label => 'Bed size (mm)',
  421. cli => 'bed-size=s',
  422. type => 'point',
  423. serialize => sub { join ',', @{$_[0]} },
  424. deserialize => sub { [ split /,/, $_[0] ] },
  425. },
  426. 'duplicate_grid' => {
  427. label => 'Copies (grid)',
  428. cli => 'duplicate-grid=s',
  429. type => 'point',
  430. serialize => sub { join ',', @{$_[0]} },
  431. deserialize => sub { [ split /,/, $_[0] ] },
  432. },
  433. 'duplicate_distance' => {
  434. label => 'Distance between copies',
  435. cli => 'duplicate-distance=f',
  436. type => 'i',
  437. aliases => [qw(multiply_distance)],
  438. },
  439. # sequential printing options
  440. 'complete_objects' => {
  441. label => 'Complete individual objects (watch out for extruder collisions)',
  442. cli => 'complete-objects',
  443. type => 'bool',
  444. },
  445. 'extruder_clearance_radius' => {
  446. label => 'Extruder clearance radius (mm)',
  447. cli => 'extruder-clearance-radius=f',
  448. type => 'i',
  449. },
  450. 'extruder_clearance_height' => {
  451. label => 'Extruder clearance height (mm)',
  452. cli => 'extruder-clearance-height=f',
  453. type => 'i',
  454. },
  455. };
  456. sub get {
  457. my $class = @_ == 2 ? shift : undef;
  458. my ($opt_key) = @_;
  459. no strict 'refs';
  460. return ${"Slic3r::$opt_key"};
  461. }
  462. sub set {
  463. my $class = @_ == 3 ? shift : undef;
  464. my ($opt_key, $value) = @_;
  465. no strict 'refs';
  466. ${"Slic3r::$opt_key"} = $value;
  467. }
  468. sub serialize {
  469. my $class = @_ == 2 ? shift : undef;
  470. my ($opt_key) = @_;
  471. return $Options->{$opt_key}{serialize}
  472. ? $Options->{$opt_key}{serialize}->(get($opt_key))
  473. : get($opt_key);
  474. }
  475. sub deserialize {
  476. my $class = @_ == 3 ? shift : undef;
  477. my ($opt_key, $value) = @_;
  478. return $Options->{$opt_key}{deserialize}
  479. ? set($opt_key, $Options->{$opt_key}{deserialize}->($value))
  480. : set($opt_key, $value);
  481. }
  482. sub save {
  483. my $class = shift;
  484. my ($file) = @_;
  485. open my $fh, '>', $file;
  486. binmode $fh, ':utf8';
  487. foreach my $opt (sort keys %$Options) {
  488. next if $Options->{$opt}{gui_only};
  489. my $value = get($opt);
  490. $value = $Options->{$opt}{serialize}->($value) if $Options->{$opt}{serialize};
  491. printf $fh "%s = %s\n", $opt, $value;
  492. }
  493. close $fh;
  494. }
  495. sub load {
  496. my $class = shift;
  497. my ($file) = @_;
  498. my %ignore = map { $_ => 1 } @Ignore;
  499. local $/ = "\n";
  500. open my $fh, '<', $file;
  501. binmode $fh, ':utf8';
  502. while (<$fh>) {
  503. s/\R+$//;
  504. next if /^\s+/;
  505. next if /^$/;
  506. next if /^\s*#/;
  507. /^(\w+) = (.*)/ or die "Unreadable configuration file (invalid data at line $.)\n";
  508. my ($key, $val) = ($1, $2);
  509. # handle legacy options
  510. next if $ignore{$key};
  511. if ($key =~ /^(?:extrusion_width|bottom_layer_speed|first_layer_height)_ratio$/) {
  512. $key = $1;
  513. $key =~ s/^bottom_layer_speed$/first_layer_speed/;
  514. $val = $val =~ /^\d+(\.\d+)?$/ ? ($val*100) . "%" : 0;
  515. }
  516. if (!exists $Options->{$key}) {
  517. $key = +(grep { $Options->{$_}{aliases} && grep $_ eq $key, @{$Options->{$_}{aliases}} }
  518. keys %$Options)[0] or warn "Unknown option $key at line $.\n";
  519. }
  520. next unless $key;
  521. my $opt = $Options->{$key};
  522. set($key, $opt->{deserialize} ? $opt->{deserialize}->($val) : $val);
  523. }
  524. close $fh;
  525. }
  526. sub validate_cli {
  527. my $class = shift;
  528. my ($opt) = @_;
  529. for (qw(start end layer)) {
  530. if (defined $opt->{$_."_gcode"}) {
  531. if ($opt->{$_."_gcode"} eq "") {
  532. set($_."_gcode", "");
  533. } else {
  534. die "Invalid value for --${_}-gcode: file does not exist"
  535. if !-e $opt->{$_."_gcode"};
  536. open my $fh, "<", $opt->{$_."_gcode"};
  537. $opt->{$_."_gcode"} = do { local $/; <$fh> };
  538. close $fh;
  539. }
  540. }
  541. }
  542. }
  543. sub validate {
  544. my $class = shift;
  545. # -j, --threads
  546. die "Invalid value for --threads\n"
  547. if $Slic3r::threads < 1;
  548. die "Your perl wasn't built with multithread support\n"
  549. if $Slic3r::threads > 1 && !$Slic3r::have_threads;
  550. # --layer-height
  551. die "Invalid value for --layer-height\n"
  552. if $Slic3r::layer_height <= 0;
  553. die "--layer-height must be a multiple of print resolution\n"
  554. if $Slic3r::layer_height / $Slic3r::scaling_factor % 1 != 0;
  555. # --first-layer-height
  556. die "Invalid value for --first-layer-height\n"
  557. if $Slic3r::first_layer_height !~ /^(?:\d+(?:\.\d+)?)%?$/;
  558. $Slic3r::_first_layer_height = $Slic3r::first_layer_height =~ /^(\d+(?:\.\d+)?)%$/
  559. ? ($Slic3r::layer_height * $1/100)
  560. : $Slic3r::first_layer_height;
  561. # --filament-diameter
  562. die "Invalid value for --filament-diameter\n"
  563. if $Slic3r::filament_diameter < 1;
  564. # --nozzle-diameter
  565. die "Invalid value for --nozzle-diameter\n"
  566. if $Slic3r::nozzle_diameter < 0;
  567. die "--layer-height can't be greater than --nozzle-diameter\n"
  568. if $Slic3r::layer_height > $Slic3r::nozzle_diameter;
  569. die "First layer height can't be greater than --nozzle-diameter\n"
  570. if $Slic3r::_first_layer_height > $Slic3r::nozzle_diameter;
  571. # calculate flow
  572. $Slic3r::flow->calculate($Slic3r::extrusion_width);
  573. $Slic3r::first_layer_flow->calculate($Slic3r::first_layer_extrusion_width)
  574. if $Slic3r::first_layer_extrusion_width;
  575. $Slic3r::perimeters_flow->calculate($Slic3r::perimeters_extrusion_width || $Slic3r::extrusion_width);
  576. $Slic3r::infill_flow->calculate($Slic3r::infill_extrusion_width || $Slic3r::extrusion_width);
  577. Slic3r::debugf "Default flow width = %s, spacing = %s, min_spacing = %d\n",
  578. $Slic3r::flow->width, $Slic3r::flow->spacing, $Slic3r::flow->min_spacing;
  579. # --perimeters
  580. die "Invalid value for --perimeters\n"
  581. if $Slic3r::perimeters < 0;
  582. # --solid-layers
  583. die "Invalid value for --solid-layers\n"
  584. if $Slic3r::solid_layers < 0;
  585. # --print-center
  586. die "Invalid value for --print-center\n"
  587. if !ref $Slic3r::print_center
  588. && (!$Slic3r::print_center || $Slic3r::print_center !~ /^\d+,\d+$/);
  589. $Slic3r::print_center = [ split /[,x]/, $Slic3r::print_center ]
  590. if !ref $Slic3r::print_center;
  591. # --fill-pattern
  592. die "Invalid value for --fill-pattern\n"
  593. if !exists $Slic3r::Fill::FillTypes{$Slic3r::fill_pattern};
  594. # --solid-fill-pattern
  595. die "Invalid value for --solid-fill-pattern\n"
  596. if !exists $Slic3r::Fill::FillTypes{$Slic3r::solid_fill_pattern};
  597. # --fill-density
  598. die "Invalid value for --fill-density\n"
  599. if $Slic3r::fill_density < 0 || $Slic3r::fill_density > 1;
  600. # --infill-every-layers
  601. die "Invalid value for --infill-every-layers\n"
  602. if $Slic3r::infill_every_layers !~ /^\d+$/ || $Slic3r::infill_every_layers < 1;
  603. die "Maximum infill thickness can't exceed nozzle diameter\n"
  604. if $Slic3r::infill_every_layers * $Slic3r::layer_height > $Slic3r::nozzle_diameter;
  605. # --scale
  606. die "Invalid value for --scale\n"
  607. if $Slic3r::scale <= 0;
  608. # --bed-size
  609. die "Invalid value for --bed-size\n"
  610. if !ref $Slic3r::bed_size
  611. && (!$Slic3r::bed_size || $Slic3r::bed_size !~ /^\d+,\d+$/);
  612. $Slic3r::bed_size = [ split /[,x]/, $Slic3r::bed_size ]
  613. if !ref $Slic3r::bed_size;
  614. # --duplicate-grid
  615. die "Invalid value for --duplicate-grid\n"
  616. if !ref $Slic3r::duplicate_grid
  617. && (!$Slic3r::duplicate_grid || $Slic3r::duplicate_grid !~ /^\d+,\d+$/);
  618. $Slic3r::duplicate_grid = [ split /[,x]/, $Slic3r::duplicate_grid ]
  619. if !ref $Slic3r::duplicate_grid;
  620. # --duplicate
  621. die "Invalid value for --duplicate or --duplicate-grid\n"
  622. if !$Slic3r::duplicate || $Slic3r::duplicate < 1 || !$Slic3r::duplicate_grid
  623. || (grep !$_, @$Slic3r::duplicate_grid);
  624. die "Use either --duplicate or --duplicate-grid (using both doesn't make sense)\n"
  625. if $Slic3r::duplicate > 1 && $Slic3r::duplicate_grid && (grep $_ && $_ > 1, @$Slic3r::duplicate_grid);
  626. $Slic3r::duplicate_mode = 'autoarrange' if $Slic3r::duplicate > 1;
  627. $Slic3r::duplicate_mode = 'grid' if grep $_ && $_ > 1, @$Slic3r::duplicate_grid;
  628. # --skirt-height
  629. die "Invalid value for --skirt-height\n"
  630. if $Slic3r::skirt_height < 0;
  631. # --bridge-flow-ratio
  632. die "Invalid value for --bridge-flow-ratio\n"
  633. if $Slic3r::bridge_flow_ratio <= 0;
  634. # extruder clearance
  635. die "Invalid value for --extruder-clearance-radius\n"
  636. if $Slic3r::extruder_clearance_radius <= 0;
  637. die "Invalid value for --extruder-clearance-height\n"
  638. if $Slic3r::extruder_clearance_height <= 0;
  639. $Slic3r::first_layer_temperature //= $Slic3r::temperature; #/
  640. $Slic3r::first_layer_bed_temperature //= $Slic3r::bed_temperature; #/
  641. # G-code flavors
  642. $Slic3r::extrusion_axis = 'A' if $Slic3r::gcode_flavor eq 'mach3';
  643. $Slic3r::extrusion_axis = '' if $Slic3r::gcode_flavor eq 'no-extrusion';
  644. # legacy with existing config files
  645. $Slic3r::small_perimeter_speed ||= $Slic3r::perimeter_speed;
  646. $Slic3r::bridge_speed ||= $Slic3r::infill_speed;
  647. $Slic3r::solid_infill_speed ||= $Slic3r::infill_speed;
  648. }
  649. sub replace_options {
  650. my $class = shift;
  651. my ($string, $more_variables) = @_;
  652. if ($more_variables) {
  653. my $variables = join '|', keys %$more_variables;
  654. $string =~ s/\[($variables)\]/$more_variables->{$1}/eg;
  655. }
  656. my @lt = localtime; $lt[5] += 1900; $lt[4] += 1;
  657. $string =~ s/\[timestamp\]/sprintf '%04d%02d%02d-%02d%02d%02d', @lt[5,4,3,2,1,0]/egx;
  658. $string =~ s/\[year\]/$lt[5]/eg;
  659. $string =~ s/\[month\]/$lt[4]/eg;
  660. $string =~ s/\[day\]/$lt[3]/eg;
  661. $string =~ s/\[hour\]/$lt[2]/eg;
  662. $string =~ s/\[minute\]/$lt[1]/eg;
  663. $string =~ s/\[second\]/$lt[0]/eg;
  664. $string =~ s/\[version\]/$Slic3r::VERSION/eg;
  665. # build a regexp to match the available options
  666. my $options = join '|',
  667. grep !$Slic3r::Config::Options->{$_}{multiline},
  668. keys %$Slic3r::Config::Options;
  669. # use that regexp to search and replace option names with option values
  670. $string =~ s/\[($options)\]/Slic3r::Config->serialize($1)/eg;
  671. return $string;
  672. }
  673. 1;