diff --git a/build.xml b/build.xml index 0ab0920e6..b2e6be064 100644 --- a/build.xml +++ b/build.xml @@ -1,4 +1,6 @@  + + @@ -26,7 +28,7 @@ - + @@ -62,7 +64,7 @@ - + + +
+
+ +
+
+ +
+ + + +
+ +
+ + +
+ + + + +
+
+ + +
+ Installation on Linux
+ + + + + + +
+ + + +

Download

+

First, make sure you've downloaded the latest version.

+

Prerequisites

+

You'll need to install a recent version of Java (1.5 or later), python 2.6 or later, and the python TkInter package. Additionally, you can speed up toolpath generation by installing the Python "psyco" package.

+

If you're using Ubuntu or a similar system, you can install all these from the command line:

+
+
+sudo apt-get install openjdk-6-jdk python python-tk python-psyco
+
+

For Ubuntu 11.04 (natty narwhal)

+

If the model preview window doesn't display properly, you will need to install a proprietary version of Java. To do so, copy and paste this into a terminal:

+
+
+sudo add-apt-repository "deb http://archive.canonical.com/ubuntu natty partner"
+sudo apt-get update
+sudo apt-get install sun-java6-jre
+
+

Next, you need to configure your system to use this version of java. Copy this into a terminal:

+
+
+sudo update-alternatives --config java
+
+

Select the '/usr/lib/jvm/java-6-sun/jre/bin/java' option (it should be option 2)

+

Optional: remove brltty

+

Some users have had issues with a Braille program that comes pre-installed in Ubuntu and may conflict with the serial driver. If you run into problems, you can remove the program with this command:

+
+
+sudo apt-get remove brltty
+
+

Unpack it

+

Unpack the ReplicatorG .tar.gz file to a folder on your desktop (or wherever you'd like to install it).

+

For Fedora 14 and higher

+

ReplicatorG 25 ships an older version of the rxtx-library which can cause trouble:

+
+
+check_group_uucp(): error testing lock file creation
+Error details:Permission denied
+check_lock_status: No permission to create lock file.
+
+

If this happens, replace the library from the replicatorg folder (replicatorg-0025/lib-i686/librxtxSerial.so) with the one from your system (/usr/lib/rxtx/librxtxSerial-*.*.so.) Change the paths accordingly if you are on a 64bit system. (replicatorg-0025/lib-x86_64 and /usr/lib64/rxtx/)

+

See http://replicatorg.lighthouseapp.com/projects/66325/tickets/181-upgrading-to-current-rxtx-library for more details on this issue.

+

For Archlinux

+

Packages requirements

+
+
+# pacman -Syu python tk
+
+

Java version

+

Unfortunately the model preview doesn't work with openjdk. Oracle proprietary version is required.
+You can install it from AUR using jre and jdk packages.
+https://aur.archlinux.org/packages.php?ID=51908
+http://aur.archlinux.org/packages.php?ID=51906

+

If you have installed aurget then you can simply type

+
+
+$ aurget -S jre jdk
+
+

Access to serial port

+

Ensure your user(s) have access to the serial port. If you are using a FTDI usb-serial adapter check rights on the file /dev/ttyUSBX, where X is the number of the corresponding serial port.

+
+
+$ ls -la /dev/ttyUSB0
+crw-rw---- 1 root uucp 4, 64 Oct  4 08:47 /dev/ttyUSB0
+
+

User root and group uucp have read/write access to the device.

+

If you are using a replicator with a built-in USB-to-serial converter check rights on the file /dev/ttyACMX, where X is the number of the corresponding serial port.

+
+
+$ ls -la /dev/ttyACM0
+crw-rw---- 1 root dialout 166, 0 Jul 23 13:54 /dev/ttyACM0
+
+

Note that /dev/ttyACMX may only exist when the replicator is connected and switched on. +

+

User root and group dialout have read/write access to /dev/ttyACMX. +

+

ReplicatorG also creates a lock file in /var/lock which on some more recent LInux version is a symlink to /run/lock +

+
+
+$ ls -ld /run/lock
+drwxrwxr-x 5 root lock 140 Jul 23 11:42 /run/lock
+
+

User root and group lock have read/write access to /run/lock. +

+

You can simply add your user(s) in the groups by editing file /etc/group as root or using your favorite GUI. In the case of the replicator with a built-in USB-to-serial converter, you may need all three groups, as some drivers test explicitly for group uucp.

+

You will probably need to logout/login to update paths and rights.

+

Run It!

+

Open the replicatorg folder and run the "replicatorg" script by double-clicking it. If you have built ReplicatorG from sources, the script may not be there. You can find it in dist/linux/replicatorg-version. Alternatively you can run it by typing

+
+$ ant run
+
+

You will have had to install ant in order to build it.

+

Done!

+

Next, move on to the usage page for instructions on configuring and using ReplicatorG.

+ +
+ + + + + + + + + +
+
+ +
+ +
+ + + + + +
+ Unless otherwise stated, the content of this page is licensed under +GNU +Free Documentation License. +
+ + + + + +
+ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/machines/cupcake/start+ABP+Sailfish.gcode b/machines/cupcake/start+ABP+Sailfish.gcode index d7df6e95d..d03414519 100755 --- a/machines/cupcake/start+ABP+Sailfish.gcode +++ b/machines/cupcake/start+ABP+Sailfish.gcode @@ -23,4 +23,5 @@ G1 X-30 Y30 Z6 F3300.0 (move to initial position) G1 Z0 F3300.0 (Go back down) M101 (start extruder, fwd) G1 X0 Y0 Z0 F2400.0 (move to origin) -(**** end of start.txt ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/cupcake/start+ABP.gcode b/machines/cupcake/start+ABP.gcode index d4a327a49..c28fc7cb2 100755 --- a/machines/cupcake/start+ABP.gcode +++ b/machines/cupcake/start+ABP.gcode @@ -21,4 +21,5 @@ G1 X-30 Y30 Z6 F3300.0 (move to initial position) G1 Z0 F3300.0 (Go back down) M101 (start extruder, fwd) G1 X0 Y0 Z0 F2400.0 (move to origin) -(**** end of start.txt ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/cupcake/start+Frostruder.gcode b/machines/cupcake/start+Frostruder.gcode index fe429d584..b542d9f31 100644 --- a/machines/cupcake/start+Frostruder.gcode +++ b/machines/cupcake/start+Frostruder.gcode @@ -14,4 +14,5 @@ G92 X0 Y0 Z0 (You are now at 0,0,0) G0 Z0 (Go back to zero.) -(**** end of start.gcode ****) \ No newline at end of file +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/cupcake/start+HBP+Sailfish.gcode b/machines/cupcake/start+HBP+Sailfish.gcode index ecb0c355a..9de1be87e 100644 --- a/machines/cupcake/start+HBP+Sailfish.gcode +++ b/machines/cupcake/start+HBP+Sailfish.gcode @@ -18,4 +18,5 @@ G04 P5000 (Wait 5 seconds) M103 (Extruder off) M01 (The heated build platform is heating up. Wait until after the lights have turned off for the first time, clear the test extrusion, and click yes.) G0 Z0 (Go back to zero.) -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/cupcake/start+HBP.gcode b/machines/cupcake/start+HBP.gcode index fcfb9d27a..f568328d0 100644 --- a/machines/cupcake/start+HBP.gcode +++ b/machines/cupcake/start+HBP.gcode @@ -16,4 +16,5 @@ G04 P5000 (Wait 5 seconds) M103 (Extruder off) M01 (The heated build platform is heating up. Wait until after the lights have turned off for the first time, clear the test extrusion, and click yes.) G0 Z0 (Go back to zero.) -(**** end of start.gcode ****) \ No newline at end of file +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/cupcake/start.gcode b/machines/cupcake/start.gcode index e786d90b8..d1e93df53 100644 --- a/machines/cupcake/start.gcode +++ b/machines/cupcake/start.gcode @@ -3,7 +3,7 @@ G21 (set units to mm) G90 (set positioning to absolute) G10 P1 X16.5 Y0 Z-0.3 (Designate T0 Offset) G10 P2 X-16.5 Y0 Z-0.3 (Designate T1 Offset) -G55 (Recall offset cooridinate system for T1) +G55 (Recall offset coordinate system for T1) M104 S225 T0 (set extruder temperature) M109 S110 T0 (set HBP temperature) (**** begin homing ****) @@ -16,4 +16,5 @@ M132 X Y Z A B (Recall stored home offsets for XYZAB axis) (**** end homing ****) M6 T0 M108 R3.0 T0 -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/replicator/Dual_Head_start.gcode b/machines/replicator/Dual_Head_start.gcode index 36b8ee407..bbb2e455b 100644 --- a/machines/replicator/Dual_Head_start.gcode +++ b/machines/replicator/Dual_Head_start.gcode @@ -23,4 +23,5 @@ G0 Z0.6 (Position Height) M108 R5.0 (Set Extruder Speed) M101 (Start Extruder) G4 P2000 (Create Anchor) -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/replicator/Single_Head_start.gcode b/machines/replicator/Single_Head_start.gcode index 5af0acd22..b0a6d9359 100644 --- a/machines/replicator/Single_Head_start.gcode +++ b/machines/replicator/Single_Head_start.gcode @@ -23,4 +23,5 @@ G0 Z0.6 (Position Height) M108 R5.0 (Set Extruder Speed) M101 (Start Extruder) G4 P2000 (Create Anchor) -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/replicator2/Dual_Head_start.gcode b/machines/replicator2/Dual_Head_start.gcode index f17529470..4f39eb503 100644 --- a/machines/replicator2/Dual_Head_start.gcode +++ b/machines/replicator2/Dual_Head_start.gcode @@ -23,4 +23,5 @@ G0 Z0.6 (Position Height) M108 R5.0 (Set Extruder Speed) M101 (Start Extruder) G4 P2000 (Create Anchor) -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/replicator2/Single_Head_start.gcode b/machines/replicator2/Single_Head_start.gcode index ce1fcdc80..26f9a4aeb 100644 --- a/machines/replicator2/Single_Head_start.gcode +++ b/machines/replicator2/Single_Head_start.gcode @@ -18,8 +18,10 @@ M6 T0 (wait for toolhead, and HBP to reach temperature) G130 X127 Y127 Z40 A127 B127 (Set Stepper motor Vref to defaults) M108 R3.0 T0 G0 X-141 Y-74 (Position Nozzle) -G0 Z0.6 (Position Height) +G0 Z0.6 (Position Height)(**** end of start.gcode ****) + M108 R5.0 (Set Extruder Speed) M101 (Start Extruder) G4 P2000 (Create Anchor) -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+ABP+Stepstruder.gcode b/machines/thingomatic/start+ABP+Stepstruder.gcode index 810af2cb5..cf3fed942 100644 --- a/machines/thingomatic/start+ABP+Stepstruder.gcode +++ b/machines/thingomatic/start+ABP+Stepstruder.gcode @@ -1,38 +1,39 @@ -(**** beginning of start.gcode ****) -(This file is for a MakerBot Thing-O-Matic) -(**** begin initialization commands ****) -G21 (set units to mm) -G90 (set positioning to absolute) -M108 R5.0 (set extruder speed) -M103 (Make sure extruder is off) -M104 S225 T0 (set extruder temperature) -M109 S100 T0 (set heated-build-platform temperature) -(**** end initialization commands ****) -(**** begin homing ****) -G162 Z F1000 (home Z axis maximum) -G92 Z10 (set Z to 0) -G1 Z0 (move z down 10) -G162 Z F150 (home Z axis maximum) -G161 X Y F2500 (home XY axes minimum) -M132 X Y Z A B (Recall stored home offsets for XYZAB axis) -(**** end homing ****) -(**** begin pre-wipe commands ****) -( Some people have had problems with the nozzle hitting ) -( bolts or wipers during this pre-extrusion warmup. ) -( If this happens to you, you can change the values for ) -( the X and Y positions in the following code. ) -( The goal is to have the toolhead wipe its initial ) -( extrusion near the edge of the platform, [anchor it] ) -( so as not to have it interfere with the print. ) -( This file can be found in: ) -( replicatorg/skein_engines/skeinforge-##/skeinforge_application/ ) -( prefs//alterations ) -G1 X25 Y-60 Z10 F3300.0 (move to waiting position) -M6 T0 (wait for toolhead parts, nozzle, HBP, etc., to reach temperature) -G0 X25 Y-57 (Position Nozzle) -G0 Z0.6 (Position Height) -M108 R4.0 (Set Extruder Speed) -M101 (Start Extruder) -G4 P1500 (Create Anchor) -(**** end pre-wipe commands ****) -(**** end of start.gcode ****) +(**** beginning of start.gcode ****) +(This file is for a MakerBot Thing-O-Matic) +(**** begin initialization commands ****) +G21 (set units to mm) +G90 (set positioning to absolute) +M108 R5.0 (set extruder speed) +M103 (Make sure extruder is off) +M104 S225 T0 (set extruder temperature) +M109 S100 T0 (set heated-build-platform temperature) +(**** end initialization commands ****) +(**** begin homing ****) +G162 Z F1000 (home Z axis maximum) +G92 Z10 (set Z to 0) +G1 Z0 (move z down 10) +G162 Z F150 (home Z axis maximum) +G161 X Y F2500 (home XY axes minimum) +M132 X Y Z A B (Recall stored home offsets for XYZAB axis) +(**** end homing ****) +(**** begin pre-wipe commands ****) +( Some people have had problems with the nozzle hitting ) +( bolts or wipers during this pre-extrusion warmup. ) +( If this happens to you, you can change the values for ) +( the X and Y positions in the following code. ) +( The goal is to have the toolhead wipe its initial ) +( extrusion near the edge of the platform, [anchor it] ) +( so as not to have it interfere with the print. ) +( This file can be found in: ) +( replicatorg/skein_engines/skeinforge-##/skeinforge_application/ ) +( prefs//alterations ) +G1 X25 Y-60 Z10 F3300.0 (move to waiting position) +M6 T0 (wait for toolhead parts, nozzle, HBP, etc., to reach temperature) +G0 X25 Y-57 (Position Nozzle) +G0 Z0.6 (Position Height) +M108 R4.0 (Set Extruder Speed) +M101 (Start Extruder) +G4 P1500 (Create Anchor) +(**** end pre-wipe commands ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+ABP.gcode b/machines/thingomatic/start+ABP.gcode index 31ae0c816..6539acf88 100644 --- a/machines/thingomatic/start+ABP.gcode +++ b/machines/thingomatic/start+ABP.gcode @@ -24,5 +24,5 @@ M101 (Extruder on, forward) G04 P5000 (Wait t/1000 seconds) M103 (Extruder off) (**** end pre-wipe commands ****) -(**** end of start.txt ****) - +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+Frostruder.gcode b/machines/thingomatic/start+Frostruder.gcode index fe429d584..b542d9f31 100644 --- a/machines/thingomatic/start+Frostruder.gcode +++ b/machines/thingomatic/start+Frostruder.gcode @@ -14,4 +14,5 @@ G92 X0 Y0 Z0 (You are now at 0,0,0) G0 Z0 (Go back to zero.) -(**** end of start.gcode ****) \ No newline at end of file +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+HBP+Stepstruder OLD.gcode b/machines/thingomatic/start+HBP+Stepstruder OLD.gcode index cf33b8c0c..9d8be957f 100644 --- a/machines/thingomatic/start+HBP+Stepstruder OLD.gcode +++ b/machines/thingomatic/start+HBP+Stepstruder OLD.gcode @@ -15,4 +15,5 @@ M132 X Y Z (Recall stored home offsets for XYZ) (**** end homing ****) M6 T0 M108 R3.0 T0 -(**** end of start.gcode ****) \ No newline at end of file +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+HBP+Stepstruder+Sailfish.gcode b/machines/thingomatic/start+HBP+Stepstruder+Sailfish.gcode index 73da689ed..bdd54ec65 100644 --- a/machines/thingomatic/start+HBP+Stepstruder+Sailfish.gcode +++ b/machines/thingomatic/start+HBP+Stepstruder+Sailfish.gcode @@ -1,40 +1,41 @@ -(**** beginning of start.gcode ****) -(This file is for a MakerBot Thing-O-Matic) -(**** begin initialization commands ****) -M103 (disable RPM) -M73 P0 (enable build progress) -G21 (set units to mm) -G90 (set positioning to absolute) -M108 R5.0 (set extruder speed) -M103 (Make sure extruder is off) -M104 S225 T0 (set extruder temperature) -M109 S100 T0 (set heated-build-platform temperature) -(**** end initialization commands ****) -(**** begin homing ****) -G162 Z F1000 (home Z axis maximum) -G92 Z10 (set Z to 0) -G1 Z0 (move z down 10) -G162 Z F150 (home Z axis maximum) -G161 X Y F2500 (home XY axes minimum) -M132 X Y Z A B (Recall stored home offsets for XYZAB axis) -(**** end homing ****) -(**** begin pre-wipe commands ****) -( Some people have had problems with the nozzle hitting ) -( bolts or wipers during this pre-extrusion warmup. ) -( If this happens to you, you can change the values for ) -( the X and Y positions in the following code. ) -( The goal is to have the toolhead wipe its initial ) -( extrusion near the edge of the platform, [anchor it] ) -( so as not to have it interfere with the print. ) -( This file can be found in: ) -( replicatorg/skein_engines/skeinforge-##/skeinforge_application/ ) -( prefs//alterations ) -G1 X25 Y-60 Z10 F3300.0 (move to waiting position) -M6 T0 (wait for toolhead parts, nozzle, HBP, etc., to reach temperature) -G0 X25 Y-57 (Position Nozzle) -G0 Z0.6 (Position Height) -M108 R4.0 (Set Extruder Speed) -M101 (Start Extruder) -G4 P1500 (Create Anchor) -(**** end pre-wipe commands ****) -(**** end of start.gcode ****) +(**** beginning of start.gcode ****) +(This file is for a MakerBot Thing-O-Matic) +(**** begin initialization commands ****) +M103 (disable RPM) +M73 P0 (enable build progress) +G21 (set units to mm) +G90 (set positioning to absolute) +M108 R5.0 (set extruder speed) +M103 (Make sure extruder is off) +M104 S225 T0 (set extruder temperature) +M109 S100 T0 (set heated-build-platform temperature) +(**** end initialization commands ****) +(**** begin homing ****) +G162 Z F1000 (home Z axis maximum) +G92 Z10 (set Z to 0) +G1 Z0 (move z down 10) +G162 Z F150 (home Z axis maximum) +G161 X Y F2500 (home XY axes minimum) +M132 X Y Z A B (Recall stored home offsets for XYZAB axis) +(**** end homing ****) +(**** begin pre-wipe commands ****) +( Some people have had problems with the nozzle hitting ) +( bolts or wipers during this pre-extrusion warmup. ) +( If this happens to you, you can change the values for ) +( the X and Y positions in the following code. ) +( The goal is to have the toolhead wipe its initial ) +( extrusion near the edge of the platform, [anchor it] ) +( so as not to have it interfere with the print. ) +( This file can be found in: ) +( replicatorg/skein_engines/skeinforge-##/skeinforge_application/ ) +( prefs//alterations ) +G1 X25 Y-60 Z10 F3300.0 (move to waiting position) +M6 T0 (wait for toolhead parts, nozzle, HBP, etc., to reach temperature) +G0 X25 Y-57 (Position Nozzle) +G0 Z0.6 (Position Height) +M108 R4.0 (Set Extruder Speed) +M101 (Start Extruder) +G4 P1500 (Create Anchor) +(**** end pre-wipe commands ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+HBP+Stepstruder.gcode b/machines/thingomatic/start+HBP+Stepstruder.gcode index 810af2cb5..cf3fed942 100644 --- a/machines/thingomatic/start+HBP+Stepstruder.gcode +++ b/machines/thingomatic/start+HBP+Stepstruder.gcode @@ -1,38 +1,39 @@ -(**** beginning of start.gcode ****) -(This file is for a MakerBot Thing-O-Matic) -(**** begin initialization commands ****) -G21 (set units to mm) -G90 (set positioning to absolute) -M108 R5.0 (set extruder speed) -M103 (Make sure extruder is off) -M104 S225 T0 (set extruder temperature) -M109 S100 T0 (set heated-build-platform temperature) -(**** end initialization commands ****) -(**** begin homing ****) -G162 Z F1000 (home Z axis maximum) -G92 Z10 (set Z to 0) -G1 Z0 (move z down 10) -G162 Z F150 (home Z axis maximum) -G161 X Y F2500 (home XY axes minimum) -M132 X Y Z A B (Recall stored home offsets for XYZAB axis) -(**** end homing ****) -(**** begin pre-wipe commands ****) -( Some people have had problems with the nozzle hitting ) -( bolts or wipers during this pre-extrusion warmup. ) -( If this happens to you, you can change the values for ) -( the X and Y positions in the following code. ) -( The goal is to have the toolhead wipe its initial ) -( extrusion near the edge of the platform, [anchor it] ) -( so as not to have it interfere with the print. ) -( This file can be found in: ) -( replicatorg/skein_engines/skeinforge-##/skeinforge_application/ ) -( prefs//alterations ) -G1 X25 Y-60 Z10 F3300.0 (move to waiting position) -M6 T0 (wait for toolhead parts, nozzle, HBP, etc., to reach temperature) -G0 X25 Y-57 (Position Nozzle) -G0 Z0.6 (Position Height) -M108 R4.0 (Set Extruder Speed) -M101 (Start Extruder) -G4 P1500 (Create Anchor) -(**** end pre-wipe commands ****) -(**** end of start.gcode ****) +(**** beginning of start.gcode ****) +(This file is for a MakerBot Thing-O-Matic) +(**** begin initialization commands ****) +G21 (set units to mm) +G90 (set positioning to absolute) +M108 R5.0 (set extruder speed) +M103 (Make sure extruder is off) +M104 S225 T0 (set extruder temperature) +M109 S100 T0 (set heated-build-platform temperature) +(**** end initialization commands ****) +(**** begin homing ****) +G162 Z F1000 (home Z axis maximum) +G92 Z10 (set Z to 0) +G1 Z0 (move z down 10) +G162 Z F150 (home Z axis maximum) +G161 X Y F2500 (home XY axes minimum) +M132 X Y Z A B (Recall stored home offsets for XYZAB axis) +(**** end homing ****) +(**** begin pre-wipe commands ****) +( Some people have had problems with the nozzle hitting ) +( bolts or wipers during this pre-extrusion warmup. ) +( If this happens to you, you can change the values for ) +( the X and Y positions in the following code. ) +( The goal is to have the toolhead wipe its initial ) +( extrusion near the edge of the platform, [anchor it] ) +( so as not to have it interfere with the print. ) +( This file can be found in: ) +( replicatorg/skein_engines/skeinforge-##/skeinforge_application/ ) +( prefs//alterations ) +G1 X25 Y-60 Z10 F3300.0 (move to waiting position) +M6 T0 (wait for toolhead parts, nozzle, HBP, etc., to reach temperature) +G0 X25 Y-57 (Position Nozzle) +G0 Z0.6 (Position Height) +M108 R4.0 (Set Extruder Speed) +M101 (Start Extruder) +G4 P1500 (Create Anchor) +(**** end pre-wipe commands ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+dual+Sailfish.gcode b/machines/thingomatic/start+dual+Sailfish.gcode index 18deec045..19183ed2d 100644 --- a/machines/thingomatic/start+dual+Sailfish.gcode +++ b/machines/thingomatic/start+dual+Sailfish.gcode @@ -6,7 +6,7 @@ G21 (set units to mm) G90 (set positioning to absolute) G10 P1 X-16.55 Y0 Z-0.3 (Designate T0 Offset) G10 P2 X16.5 Y0 Z-0.3 (Designate T1 Offset) -G55 (Recall offset cooridinate system) +G55 (Recall offset coordinate system) M104 S225 T0 (set extruder temperature) M104 S225 T1 (set extruder temperature) M109 S110 T0 (set HBP temperature) @@ -20,4 +20,5 @@ M132 X Y Z A B (Recall stored home offsets for XYZAB axis) (**** end homing ****) M6 T0 M6 T1 -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+dual+single+Sailfish.gcode b/machines/thingomatic/start+dual+single+Sailfish.gcode index bc6a7702b..60576e757 100644 --- a/machines/thingomatic/start+dual+single+Sailfish.gcode +++ b/machines/thingomatic/start+dual+single+Sailfish.gcode @@ -6,7 +6,7 @@ G21 (set units to mm) G90 (set positioning to absolute) G10 P1 X16.55 Y0 Z-0.3 (Designate T0 Offset) G10 P2 X-16.5 Y0 Z-0.3 (Designate T1 Offset) -G55 (Recall offset cooridinate system) +G55 (Recall offset coordinate system) M104 S225 T0 (set extruder temperature) M109 S110 T0 (set HBP temperature) (**** begin homing ****) @@ -19,4 +19,5 @@ M132 X Y Z A B (Recall stored home offsets for XYZAB axis) (**** end homing ****) M6 T0 M6 T1 -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+dual+single.gcode b/machines/thingomatic/start+dual+single.gcode index 2739fcbd9..eb8072837 100644 --- a/machines/thingomatic/start+dual+single.gcode +++ b/machines/thingomatic/start+dual+single.gcode @@ -4,7 +4,7 @@ G21 (set units to mm) G90 (set positioning to absolute) G10 P1 X16.55 Y0 Z-0.3 (Designate T0 Offset) G10 P2 X-16.5 Y0 Z-0.3 (Designate T1 Offset) -G55 (Recall offset cooridinate system) +G55 (Recall offset coordinate system) M104 S225 T0 (set extruder temperature) M109 S110 T0 (set HBP temperature) (**** begin homing ****) @@ -17,4 +17,5 @@ M132 X Y Z A B (Recall stored home offsets for XYZAB axis) (**** end homing ****) M6 T0 M6 T1 -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/machines/thingomatic/start+dual.gcode b/machines/thingomatic/start+dual.gcode index b03f54fa5..1545174a5 100644 --- a/machines/thingomatic/start+dual.gcode +++ b/machines/thingomatic/start+dual.gcode @@ -4,7 +4,7 @@ G21 (set units to mm) G90 (set positioning to absolute) G10 P1 X-16.55 Y0 Z-0.3 (Designate T0 Offset) G10 P2 X16.5 Y0 Z-0.3 (Designate T1 Offset) -G55 (Recall offset cooridinate system) +G55 (Recall offset coordinate system) M104 S225 T0 (set extruder temperature) M104 S225 T1 (set extruder temperature) M109 S110 T0 (set HBP temperature) @@ -18,4 +18,5 @@ M132 X Y Z A B (Recall stored home offsets for XYZAB axis) (**** end homing ****) M6 T0 M6 T1 -(**** end of start.gcode ****) +(Don't remove the in the next line - it's needed for dual extrusion.) +( **** end of start.gcode ****) diff --git a/readme.txt b/readme.txt index 7df7b50b6..f1fdb5514 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,8 @@ -ReplicatorG is an open-source GCode based controller for RepRap / CNC machines. It has 3 main goals: +ReplicatorG is an open-source GCode based controller for RepRap / CNC machines. + +This version was forked from makerbot/ReplicatorG, which unfortunately seems to have been orphaned. This version has various bug fixes and improvements including better DualStrusion code. + +ReplicatorG has 3 main goals: 1. Be as simple to use, and as easy to install as possible. 2. Be driver oriented and abstract the GCode away, allowing users to easily create drivers for their own machine. diff --git a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.analyze_plugins.skeinlayer.html b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.analyze_plugins.skeinlayer.html index 2415bda3a..11835c807 100644 --- a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.analyze_plugins.skeinlayer.html +++ b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.analyze_plugins.skeinlayer.html @@ -38,6 +38,7 @@     Viewpoint Move
  Numeric Pointer
  Scale
+  Font scale factor
  Screen Inset
    Screen Horizontal Inset
    Screen Vertical Inset
@@ -133,9 +134,19 @@
The scale setting is the scale of the image in pixels per millimeter, the higher the number, the greater the size of the display.

-The zoom in mouse tool will zoom in the display at the point where the mouse was clicked, increasing the scale by a factor of two. The zoom out tool will zoom out the display at the point where the mouse was clicked, decreasing the scale by a factor of two.
-
-

Screen Inset

+The zoom in mouse tool will zoom in the display at the point where the mouse was clicked, increasing the scale by a factor of two. The zoom out tool will zoom out the display at the point where the mouse was clicked, decreasing the scale by a factor of two.

+

Font scale factor

+ +Default is 2.0

+ +This adjusts for the scaling between the text sizes reported by the font +software and the number of screen pixels needed. If the numbers on the scale +ruler at the left of the picture displayed by running skeinlayer look a bit +crowded, increase it a bit: if there is too much empty space, +decrease it a bit. The default of 2.0 should be about right +for a 72 dots per inch monitor. +

+

Screen Inset

Screen Horizontal Inset

@@ -507,4 +518,4 @@         Enrique Perez (perez_enrique@yahoo.com) - \ No newline at end of file + diff --git a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.dimension.html b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.dimension.html index ae40af976..5cf778a57 100644 --- a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.dimension.html +++ b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.dimension.html @@ -21,7 +21,8 @@
http://objects.reprap.org/wiki/3D-to-5D-Gcode.php

-The dimension manual page is at:
+The original dimension manual page is at:
+This page describes the modified version in this release of ReplicatorG.

http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Dimension

@@ -41,6 +42,7 @@     Filament Packing Density
  Maximum E Value before Reset
  Minimum Travel for Retraction
+  Z Distance Multiplier
  Retract Within Island
  Retraction Distance
  Restart Extra Distance
@@ -104,6 +106,12 @@
Defines the minimum distance that the extruder head has to travel from the end of one thread to the beginning of another, in order to trigger the extruder retraction. Setting this to a high value means the extruder will retract only occasionally, setting it to a low value means the extruder will retract most of the time.

+

Z Distance Multiplier

+ +Default: 10
+
+Defines the multiplier that is applied to the Z distance when calculating a distance to compare with the Minimum Travel for Retraction. This is set to a large value to force Filament Retraction before a layer change. Dual Extrusion inserts tool switches on a layer change, so this should prevent filament oozing out of the extruder which is currently inactive. It can be set to 1 if you never use Dual Extrusion.
+

Retract Within Island

Default is off.
diff --git a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.export.html b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.export.html index 8cda68c8e..350977b05 100644 --- a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.export.html +++ b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.export.html @@ -13,10 +13,13 @@ Previous / Next / Contents


-Export is a craft tool to pick an export plugin, add information to the file name, and delete comments.
+Export is a craft tool to pick an export plugin, add information to the file name, and delete selected comments.

-The export manual page is at:
+The original export manual page is at:
+This page described the modified version in this release of ReplicatorG.
+
http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Export
+This page describes the modified version in this release of ReplicatorG.


Operation
@@ -26,10 +29,17 @@   Add Timestamp Extension
  Also Send Output To
  Analyze Gcode
-  Comment Choice
-    Do Not Delete Comments
-    Delete Crafting Comments
-    Delete All Comments
+  Comment Deletion Choices
+    Delete <keep> Comments
+    Delete Trace Comments
+    Delete <layer> Comments
+    Delete Settings Comments
+    Delete Other Initialisation Comments
+    Delete Other Preface Comments
+    Delete Other Crafting Comments
+    Delete Other Tagged Comments
+    Delete Other Starred Comments
+    Delete All Other Comments
  Export Operations
  File Extension
  Name of Replace File
@@ -92,22 +102,73 @@
When selected, the penultimate gcode will be sent to the analyze plugins to be analyzed and viewed.

-

Comment Choice

+

Comment Deletion Choices

+This section specifies which comments, if any, should be deleted during export.
+
+

Delete <keep> Comments

+Default is unchecked.
+
+ +If checked, any preface comments starting with <keep> are removed. The code as shipped does not generate any <keep> comments, but user modifications may add some. They can be useful for recording information like the profile or version used to generate the gcode, if other comments are being deleted. +
+
+

Delete Trace Comments

+Default is unchecked.
+
+ +If checked, any preface comments starting with <trace> are removed. The code as shipped does not generate any <trace> comments, but there is a debugging aid which adds some. +
+
+

Delete <layer> Comments

+Default is unchecked.
+
-Default is 'Delete All Comments'.
+If checked, any preface comments starting with <layer> are removed. The Dual Extrusion gcode merge logic requires the <layer> comments to be left in, so this box should normally remain unchecked unless you have a single extruder printer and never use Dual Extrusion. +
+
+

Delete Settings Comments

+Default is unchecked.
+
+ +If checked, the block of comments near the start of the gcode reporting the settings used are removed.
+
+

Delete Other Initialisation Comments

+Default is unchecked.
+
+ +If checked, the block of comments near the start of the gcode +between (<extruderInitialization>) and (</extruderInitialization>), apart from any described above, are removed.
+
+

Delete Other Preface Comments

+Default is unchecked.
+
+ +If checked, any preface comments [before (<alteration>)] not mentioned above are removed. If Alteration is not enabled, all comments are preface comments.
+
+

Delete Other Crafting Comments

+Default is unchecked.

-

Do Not Delete Comments

-When selected, export will not delete comments. Crafting comments slow down the processing in many firmware types, which leads to pauses and therefore a lower quality print.
+If checked, all comments between (<crafting>) and (</crafting>), other than those described above, are removed. You will usually not want these unless you are debugging the gcode generator. <layer> comments are described above, so checking this option does not remove them unless the Delete <layer> Comments option is also checked.
+
+

Delete Other Tagged Comments

+Default is unchecked.

-

Delete Crafting Comments

-When selected, export will delete the time consuming crafting comments, but leave the initialization comments. Since the crafting comments are deleted, there are no pauses during extrusion. The remaining initialization comments provide some useful information for the analyze tools.
+If checked, all comments starting with '(<', other than those described above, are removed.
+
+

Delete Other Starred Comments

+Default is unchecked.

-

Delete All Comments

-When selected, export will delete all comments. The comments are not necessary to run a fabricator. Some printers do not support comments at all so the safest way is choose this option.
+If checked, all comments starting with '(*', other than those described above, are removed..
+
+

Delete All Other Comments

+Default is unchecked.

+ +If checked, all comments other than those described above are removed.
+

Export Operations

Export presents the user with a choice of the export plugins in the export_plugins folder. The chosen plugin will then modify the gcode or translate it into another format. There is also the "Do Not Change Output" choice, which will not change the output. An export plugin is a script in the export_plugins folder which has the getOutput function, the globalIsReplaceable variable and if it's output is not replaceable, the writeOutput function.
diff --git a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.oozebane.html b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.oozebane.html index ebc8a805f..827f46cb9 100644 --- a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.oozebane.html +++ b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.oozebane.html @@ -63,7 +63,7 @@ Default is twenty.

-The longer the extruder has been off, the earlier the extruder will turn back on, the ratio is one minus one over e to the power of the distance the extruder has been off over the "Early Startup Distance Constant".
+The longer the extruder has been off, the earlier the extruder will turn back on, the ratio is one minus one over e to the power of the distance the extruder has been off over the "Early Startup Distance Constant". Increasing this constant makes the extruder start up later.

First Early Startup Distance

@@ -251,4 +251,4 @@         Enrique Perez (perez_enrique@yahoo.com) - \ No newline at end of file + diff --git a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.temperature.html b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.temperature.html index 90e66f3dd..ec9cfde07 100644 --- a/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.temperature.html +++ b/skein_engines/skeinforge-50/documentation/skeinforge_application.skeinforge_plugins.craft_plugins.temperature.html @@ -44,18 +44,26 @@

Rate

-The default cooling rate and heating rate for the extruder were both been derived from bothacker's graph at:
-http://bothacker.com/wp-content/uploads/2009/09/18h5m53s9.29.2009.png
-
+The default cooling rate and heating rate for the extruder were both been derived from bothacker's graph at http://fabmetheus.crsndoo.com/wiki/index.php/File:Bothacker_temperature_graph.png: +

+ + + + +

Cooling Rate

-Default is three degrees Celcius per second.
+Default is three degrees Celsius per second.

Defines the cooling rate of the extruder.

Heating Rate

-Default is ten degrees Celcius per second.
+Default is ten degrees Celsius per second.

Defines the heating rate of the extruder.

@@ -63,46 +71,51 @@

Base Temperature

-Default for ABS is two hundred degrees Celcius.
+Default for ABS is two hundred degrees Celsius.

Defines the raft base temperature.

Interface Temperature

-Default for ABS is two hundred degrees Celcius.
+Default for ABS is two hundred degrees Celsius.

Defines the raft interface temperature.

Object First Layer Infill Temperature

-Default for ABS is 195 degrees Celcius.
+Default for ABS is 195 degrees Celsius.

Defines the infill temperature of the first layer of the object.

Object First Layer Perimeter Temperature

-Default for ABS is two hundred and twenty degrees Celcius.
+Default for ABS is two hundred and twenty degrees Celsius.

Defines the edge temperature of the first layer of the object.
+Currently (version 0040) this value is ignored: the Object First Layer Infill Temperature is used instead. This may get fixed in some future version.

Object Next Layers Temperature

-Default for ABS is two hundred and thirty degrees Celcius.
+Default for ABS is two hundred and thirty degrees Celsius.

Defines the temperature of the next layers of the object.

Support Layers Temperature

-Default for ABS is two hundred degrees Celcius.
+Default for ABS is two hundred degrees Celsius.

Defines the support layers temperature.

Supported Layers Temperature

-Default for ABS is two hundred and thirty degrees Celcius.
+Default for ABS is two hundred and thirty degrees Celsius.

Defines the temperature of the supported layers of the object, those layers which are right above a support layer.

+
Note: The temperatures that are use for each of the above layers is dependent on the type of polymer used and also to some extent the ambient
+temperature of the environment and the accuracy of the thermistor in the print head. Guide temperatures are given for each material and can
+be accessed via the Polymers page.
+

Examples


diff --git a/skein_engines/skeinforge-50/fabmetheus_utilities/archive.py b/skein_engines/skeinforge-50/fabmetheus_utilities/archive.py index 9424e3870..49d33973b 100644 --- a/skein_engines/skeinforge-50/fabmetheus_utilities/archive.py +++ b/skein_engines/skeinforge-50/fabmetheus_utilities/archive.py @@ -372,9 +372,19 @@ def writeFileMessageEnd(end, fileName, fileText, message): def writeFileText(fileName, fileText, writeMode='w+'): 'Write a text to a file.' + try: + if os.path.exists(fileName): + os.rename(fileName, fileName+ '~') + except OSError: + print('File "' + fileName + '" cannot be renamed to "' + fileName + '~": ' + strerror(errno)) + return try: file = open(fileName, writeMode) + except OSError: + print('File "' + fileName + '" cannot be opened for writing: ' + strerror(errno)) + return + try: file.write(fileText) file.close() - except IOError: - print('The file ' + fileName + ' can not be written to.') + except OSError: + print('File "' + fileName + '" cannot be written to: ' + strerror(errno)) diff --git a/skein_engines/skeinforge-50/fabmetheus_utilities/euclidean.py b/skein_engines/skeinforge-50/fabmetheus_utilities/euclidean.py index 24708e025..e0739a4c8 100644 --- a/skein_engines/skeinforge-50/fabmetheus_utilities/euclidean.py +++ b/skein_engines/skeinforge-50/fabmetheus_utilities/euclidean.py @@ -1856,10 +1856,14 @@ def isWithinChannel( channelRadius, pointIndex, loop ): point = loop[pointIndex] behindSegmentComplex = loop[(pointIndex + len(loop) - 1) % len(loop)] - point behindSegmentComplexLength = abs( behindSegmentComplex ) + if behindSegmentComplexLength == 0.0: + return True if behindSegmentComplexLength < channelRadius: return True aheadSegmentComplex = loop[(pointIndex + 1) % len(loop)] - point aheadSegmentComplexLength = abs( aheadSegmentComplex ) + if aheadSegmentComplexLength == 0.0: + return True if aheadSegmentComplexLength < channelRadius: return True behindSegmentComplex /= behindSegmentComplexLength diff --git a/skein_engines/skeinforge-50/fabmetheus_utilities/fabmetheus_tools/fabmetheus_interpret.py b/skein_engines/skeinforge-50/fabmetheus_utilities/fabmetheus_tools/fabmetheus_interpret.py index 65de7cf73..7d3832375 100644 --- a/skein_engines/skeinforge-50/fabmetheus_utilities/fabmetheus_tools/fabmetheus_interpret.py +++ b/skein_engines/skeinforge-50/fabmetheus_utilities/fabmetheus_tools/fabmetheus_interpret.py @@ -119,7 +119,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.interpret.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Interpret', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Interpret') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.analyze_plugins.interpret.html') self.activateInterpret = settings.BooleanSetting().getFromValue('Activate Interpret', self, False ) self.printInterpretion = settings.BooleanSetting().getFromValue('Print Interpretion', self, False ) self.textProgram = settings.StringSetting().getFromValue('Text Program:', self, 'webbrowser') diff --git a/skein_engines/skeinforge-50/fabmetheus_utilities/gcodec.py b/skein_engines/skeinforge-50/fabmetheus_utilities/gcodec.py index b348674a9..4cf47bb35 100644 --- a/skein_engines/skeinforge-50/fabmetheus_utilities/gcodec.py +++ b/skein_engines/skeinforge-50/fabmetheus_utilities/gcodec.py @@ -28,7 +28,7 @@ import os import sys import traceback - +import inspect __author__ = 'Enrique Perez (perez_enrique@yahoo.com)' __date__ = '$Date: 2008/21/04 $' @@ -386,6 +386,12 @@ def addTagBracketedProcedure(self, procedure): 'Add a begin procedure tag, procedure and end procedure tag.' self.addLine(getTagBracketedProcedure(procedure)) + def addTraceLine(self, string): + caller = inspect.getframeinfo(inspect.currentframe().f_back) + leafName = os.path.basename(str(caller[0])) + self.addLine("( " + leafName + " line " + str(caller[1]) + + ": " + string + ")") + def getBoundaryLine(self, location): 'Get boundary gcode line.' return '( X%s Y%s Z%s )' % (self.getRounded(location.x), self.getRounded(location.y), self.getRounded(location.z)) diff --git a/skein_engines/skeinforge-50/fabmetheus_utilities/settings.py b/skein_engines/skeinforge-50/fabmetheus_utilities/settings.py index 579208b37..60d23331a 100644 --- a/skein_engines/skeinforge-50/fabmetheus_utilities/settings.py +++ b/skein_engines/skeinforge-50/fabmetheus_utilities/settings.py @@ -19,6 +19,7 @@ import webbrowser try: import Tkinter + import tkFont except: print('You do not have Tkinter, which is needed for the graphical interface, you will only be able to use the command line.') print('Information on how to download Tkinter is at:\nwww.tcl.tk/software/tcltk/') @@ -190,7 +191,10 @@ def getDisplayedDialogFromConstructor(repository): "Display the repository dialog." try: getReadRepository(repository) - return RepositoryDialog( repository, Tkinter.Tk() ) + tk = Tkinter.Tk() + for f in tk.splitlist(tk.call("font", "names")): + tkFont.nametofont(f).configure(size=10) + return RepositoryDialog( repository, tk ) except: print('this should never happen, getDisplayedDialogFromConstructor in settings could not open') print(repository) @@ -449,7 +453,7 @@ def openWebPage( webPagePath ): def printProgress(layerIndex, procedureName): "Print layerIndex followed by a carriage return." - printProgressByString('%s layer count %s...' % (procedureName.capitalize(), layerIndex + 1)) + printProgressByString(' %s layer count %s...' % (procedureName.capitalize(), layerIndex + 1)) def printProgressByNumber(layerIndex, numberOfLayers, procedureName): "Print layerIndex and numberOfLayers followed by a carriage return." @@ -586,10 +590,6 @@ def setSpinColor( setting ): def startMainLoopFromConstructor(repository): "Display the repository dialog and start the main loop." - try: - import Tkinter - except: - return displayedDialogFromConstructor = getDisplayedDialogFromConstructor(repository) if displayedDialogFromConstructor == None: print('Warning, displayedDialogFromConstructor in settings is none, so the window will not be displayed.') @@ -869,12 +869,17 @@ def getFromPath( self, important, name, path, repository ): repository.displayEntities.append(self) return self +def setFontRecursive(w, f): + if 'font' in w.keys(): + w.configure(font=f) + for child in w.winfo_children(): + setFontRecursive(child, f) class FileHelpMenuBar: def __init__( self, root ): "Create a menu bar with a file and help menu." self.underlineLetters = [] - self.menuBar = Tkinter.Menu( root ) + self.menuBar = Tkinter.Menu( root) self.root = root root.config( menu = self.menuBar ) self.fileMenu = Tkinter.Menu( self.menuBar, tearoff = 0 ) @@ -922,6 +927,8 @@ def saveClose(self): self.saveFunction() self.closeFunction() + def setFont(self, f): + setFontRecursive(self.menuBar, f) class FileNameInput( StringSetting ): "A class to display, read & write a fileName." diff --git a/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator 2 slicing defaults/alterations/end.gcode b/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator 2 slicing defaults/alterations/end.gcode index 024eb3ce0..e5d6f35c0 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator 2 slicing defaults/alterations/end.gcode +++ b/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator 2 slicing defaults/alterations/end.gcode @@ -1,4 +1,4 @@ -(******* End.gcode*******) +(******* beginning of End.gcode*******) M73 P100 (end build progress ) G0 Z155 M18 diff --git a/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator 2 slicing defaults/alterations/start.gcode b/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator 2 slicing defaults/alterations/start.gcode index 6fe511055..97334e403 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator 2 slicing defaults/alterations/start.gcode +++ b/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator 2 slicing defaults/alterations/start.gcode @@ -27,4 +27,5 @@ G0 Z0.6 (Position Height) M108 R4.0 (Set Extruder Speed) M101 (Start Extruder) G4 P1500 (Create Anchor) +(Don't remove the in the next line - it's needed for dual extrusion.) (**** end of start.gcode ****) diff --git a/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator slicing defaults/alterations/end.gcode b/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator slicing defaults/alterations/end.gcode index 024eb3ce0..e5d6f35c0 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator slicing defaults/alterations/end.gcode +++ b/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator slicing defaults/alterations/end.gcode @@ -1,4 +1,4 @@ -(******* End.gcode*******) +(******* beginning of End.gcode*******) M73 P100 (end build progress ) G0 Z155 M18 diff --git a/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator slicing defaults/alterations/start.gcode b/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator slicing defaults/alterations/start.gcode index 6fe511055..97f0d7d0b 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator slicing defaults/alterations/start.gcode +++ b/skein_engines/skeinforge-50/skeinforge_application/prefs/Replicator slicing defaults/alterations/start.gcode @@ -5,7 +5,7 @@ G21 (set units to mm) G90 (set positioning to absolute) G10 P1 X16.5 Y0 Z-0.3 (Designate T0 Offset) G10 P2 X-16.5 Y0 Z-0.3 (Designate T1 Offset) -G55 (Recall offset cooridinate system for T1) +G55 (Recall offset coordinate system for T1) M104 S220 T0 (set extruder temperature) M109 S100 T0 (set HBP temperature) (**** begin homing ****) @@ -27,4 +27,5 @@ G0 Z0.6 (Position Height) M108 R4.0 (Set Extruder Speed) M101 (Start Extruder) G4 P1500 (Create Anchor) +(Don't remove the in the next line - it's needed for dual extrusion.) (**** end of start.gcode ****) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge.py index ffe699917..b8b083ad6 100755 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge.py @@ -623,7 +623,7 @@ def main(): (moduleName, prefSpec) = prefSpec.split(':', 1) (prefName, valueName) = prefSpec.split('=', 1) #settings.addPreferenceOverride(moduleName, prefName, valueName) - settings.temporaryAddPreferenceOverride(moduleName, prefName, valueName) + #settings.temporaryAddPreferenceOverride(moduleName, prefName, valueName) sys.argv = [sys.argv[0]] + args if len( args ) > 0: writeOutput( ' '.join(args) ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/analyze_utilities/tableau.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/analyze_utilities/tableau.py index a52555205..e36f62a20 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/analyze_utilities/tableau.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/analyze_utilities/tableau.py @@ -119,6 +119,10 @@ def addAnimation(self): def addScaleScreenSlide(self): 'Add the scale, screen and slide show settings.' self.scale = settings.FloatSpinNotOnMenu().getFromValue( 10.0, 'Scale (pixels per millimeter):', self, 50.0, 15.0 ) + # This is needed to adjust for the ratio between the numbers + # reported by measure() and the pixel density of the monitor. + # unfortunately there seems to be no reliable way of calculating it. + self.pixelmagic = settings.FloatSpinNotOnMenu().getFromValue( 0.1, 'Font scale factor:', self, 10.0, 2.0 ) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Screen Inset -', self ) self.screenHorizontalInset = settings.IntSpin().getFromValue( 80, 'Screen Horizontal Inset (pixels):', self, 1000, 100 ) @@ -154,10 +158,7 @@ def addCanvasMenuRootScrollSkein(self, repository, skein, suffix, title): self.gridPosition.master = self.root self.highlightThickness = 3 self.root.title(os.path.basename(skein.fileName) + ' - ' + title) - self.rulingExtent = 24 self.rulingTargetSeparation = 150.0 - self.screenSize = skein.screenSize - self.skein = skein self.skeinPanes = skein.skeinPanes self.suffix = suffix self.timerID = None @@ -177,8 +178,8 @@ def addCanvasMenuRootScrollSkein(self, repository, skein, suffix, title): self.gridPosition = settings.GridHorizontal(2, 99) self.gridPosition.master = self.root self.gcodeStringVar = settings.Tkinter.StringVar(self.root) - self.gcodeLabel = settings.Tkinter.Label(self.root, anchor = settings.Tkinter.W, textvariable = self.gcodeStringVar) - self.gcodeLabel.grid(row = 0, column = 5, columnspan = 93, sticky = settings.Tkinter.W) + self.gcodeLabel = settings.Tkinter.Label(self.root, anchor = settings.Tkinter.W, textvariable = self.gcodeStringVar, font = self.sizedfont) + self.gcodeLabel.grid(row = 0, column = 5, columnspan = 50, sticky = settings.Tkinter.W) from fabmetheus_utilities.hidden_scrollbar import HiddenScrollbar self.xScrollbar = HiddenScrollbar(self.root, orient = settings.Tkinter.HORIZONTAL) self.xScrollbar.grid(row = 98, column = 2, columnspan = 96, sticky = settings.Tkinter.E + settings.Tkinter.W) @@ -197,16 +198,17 @@ def addCanvasMenuRootScrollSkein(self, repository, skein, suffix, title): ExportCanvasDialog().addPluginToMenu(self.canvas, skein.fileName, self.exportMenu, exportCanvasPluginFileName, suffix) self.fileHelpMenuBar.fileMenu.add_separator() self.fileHelpMenuBar.completeMenu(self.close, repository, self.save, self) + self.fileHelpMenuBar.setFont(self.sizedfont) def addLayer( self, gridPosition ): 'Add the layer frame items.' self.diveButton = self.getPhotoButtonGridIncrement( self.dive, 'dive.ppm', gridPosition ) self.soarButton = self.getPhotoButtonGridIncrement( self.soar, 'soar.ppm', gridPosition ) gridPosition.increment() - settings.Tkinter.Label( gridPosition.master, text = 'Layer:').grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) + settings.Tkinter.Label( gridPosition.master, text = 'Layer:', font = self.sizedfont).grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) gridPosition.increment() self.limitIndex() - self.layerEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.layerEntryReturnPressed, from_ = 0, increment = 1, to = getLengthMinusOneMinimumOne( self.skeinPanes ) ) + self.layerEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.layerEntryReturnPressed, from_ = 0, increment = 1, to = getLengthMinusOneMinimumOne( self.skeinPanes ), font = self.sizedfont ) self.layerEntry.bind('', self.layerEntryReturnPressed ) self.layerEntry.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) @@ -215,9 +217,9 @@ def addLine( self, gridPosition ): self.lineDiveButton = self.getPhotoButtonGridIncrement( self.lineDive, 'dive.ppm', gridPosition ) self.lineSoarButton = self.getPhotoButtonGridIncrement( self.lineSoar, 'soar.ppm', gridPosition ) gridPosition.increment() - settings.Tkinter.Label( gridPosition.master, text = 'Line:').grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) + settings.Tkinter.Label( gridPosition.master, text = 'Line:', font = self.sizedfont).grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) gridPosition.increment() - self.lineEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.lineEntryReturnPressed, from_ = 0, increment = 1, to = getLengthMinusOneMinimumOne( self.getColoredLines() ) ) + self.lineEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.lineEntryReturnPressed, from_ = 0, increment = 1, to = getLengthMinusOneMinimumOne( self.getColoredLines() ), font = self.sizedfont ) self.lineEntry.bind('', self.lineEntryReturnPressed ) self.lineEntry.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) @@ -290,7 +292,7 @@ def addPhotoImage( self, fileName, gridPosition ): 'Get a PhotoImage button, grid the button and increment the grid position.' photoImage = None try: - photoImage = settings.Tkinter.PhotoImage( file = os.path.join( self.imagesDirectoryPath, fileName ), master = gridPosition.master ) + photoImage = settings.Tkinter.PhotoImage( file = os.path.join( self.imagesDirectoryPath, fileName ), master = gridPosition.master) except: print('Image %s was not found in the images directory, so a text button will be substituted.' % fileName ) untilDotFileName = archive.getUntilDot(fileName) @@ -302,15 +304,15 @@ def addScale( self, gridPosition ): self.addMouseInstantTool('zoom_out.ppm', gridPosition, zoom_out.getNewMouseTool() ) self.addMouseInstantTool('zoom_in.ppm', gridPosition, zoom_in.getNewMouseTool() ) gridPosition.increment() - settings.Tkinter.Label( gridPosition.master, text = 'Scale:').grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) + settings.Tkinter.Label( gridPosition.master, text = 'Scale:', font = self.sizedfont).grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) gridPosition.increment() - self.scaleEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.scaleEntryReturnPressed, from_ = 10.0, increment = 5.0, to = 100.0 ) + self.scaleEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.scaleEntryReturnPressed, from_ = 10.0, increment = 5.0, to = 100.0 , font = self.sizedfont) self.scaleEntry.bind('', self.scaleEntryReturnPressed ) self.scaleEntry.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) def addSettingsMenuSetWindowGeometry( self, center ): 'Add the settings menu, center the scroll region, update, and set the window geometry.' - self.settingsMenu = settings.Tkinter.Menu( self.fileHelpMenuBar.menuBar, tearoff = 0 ) + self.settingsMenu = settings.Tkinter.Menu( self.fileHelpMenuBar.menuBar, tearoff = 0, font = self.sizedfont ) self.fileHelpMenuBar.addMenuToMenuBar( 'Settings', self.settingsMenu ) settings.addMenuEntitiesToMenuFrameable( self.settingsMenu, self.repository.menuEntities ) self.relayXview( settings.Tkinter.MOVETO, center.real - self.canvasScreenCenter.real ) @@ -426,7 +428,7 @@ def getDrawnLineText( self, location, tags, text ): anchorTowardCenter += settings.Tkinter.E else: anchorTowardCenter += settings.Tkinter.W - return self.canvas.create_text( int( location.real ), int( location.imag ), anchor = anchorTowardCenter, tags = tags, text = text ) + return self.canvas.create_text( int( location.real ), int( location.imag ), anchor = anchorTowardCenter, tags = tags, text = text, font = self.sizedfont ) def getEntityFromName(self, name): 'Get the entity of the given name.' @@ -440,7 +442,7 @@ def getPhotoButtonGridIncrement( self, commandFunction, fileName, gridPosition ) gridPosition.increment() untilDotFileName = self.addPhotoImage( fileName, gridPosition ) photoImage = self.photoImages[ untilDotFileName ] - photoButton = settings.Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', command = commandFunction, text = untilDotFileName ) + photoButton = settings.Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', command = commandFunction, text = untilDotFileName, font = 'TkDefaultFont') if photoImage != None: photoButton['image'] = photoImage photoButton.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/clairvoyance.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/clairvoyance.py index 55698f550..4f6056e32 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/clairvoyance.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/clairvoyance.py @@ -93,7 +93,7 @@ class ClairvoyanceRepository: def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.clairvoyance.html', self) - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Clairvoyance') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.analyze_plugins.clairvoyance.html') self.activateClairvoyance = settings.BooleanSetting().getFromValue('Activate Clairvoyance', self, False) settings.LabelSeparator().getFromRepository(self) self.fileNameInput = settings.FileNameInput().getFromFileName([('Gcode text files', '*.gcode')], 'Open File to Generate Clairvoyances for', self, '') diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/comment.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/comment.py index 42bfcd1fa..bec71066a 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/comment.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/comment.py @@ -76,7 +76,7 @@ class CommentRepository: def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.comment.html', self) - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Comment') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.analyze_plugins.comment.html') self.activateComment = settings.BooleanSetting().getFromValue('Activate Comment', self, False ) self.fileNameInput = settings.FileNameInput().getFromFileName( [ ('Gcode text files', '*.gcode') ], 'Open File to Write Comments for', self, '') self.executeTitle = 'Write Comments' diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/skeiniso.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/skeiniso.py index 180f5c9d8..1244e06ad 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/skeiniso.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/skeiniso.py @@ -239,6 +239,8 @@ from skeinforge_application.skeinforge_utilities import skeinforge_profile import math import sys +import Tkinter +import tkFont __author__ = 'Enrique Perez (perez_enrique@yahoo.com)' @@ -301,7 +303,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.skeiniso.html', self) self.baseNameSynonym = 'behold.csv' self.fileNameInput = settings.FileNameInput().getFromFileName( [ ('Gcode text files', '*.gcode') ], 'Open File for Skeiniso', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Skeiniso') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.analyze_plugins.skeiniso.html') self.activateSkeiniso = settings.BooleanSetting().getFromValue('Activate Skeiniso', self, False) self.addAnimation() self.axisRulings = settings.BooleanSetting().getFromValue('Axis Rulings', self, True ) @@ -639,6 +641,9 @@ def __init__( self, modelDistance, roundedRulingText ): class SkeinWindow( tableau.TableauWindow ): def __init__( self, repository, skein ): "Initialize the skein window." + self.sizedfont = tkFont.nametofont('TkDefaultFont').copy() + self.screenSize = skein.screenSize + self.skein = skein self.arrowshape = ( 24, 30, 9 ) self.addCanvasMenuRootScrollSkein( repository, skein, '_skeiniso', 'Skeiniso') self.center = 0.5 * self.screenSize @@ -680,11 +685,17 @@ def __init__( self, repository, skein ): self.addMouseToolsBind() self.negativeRulings = [] self.positiveRulings = [] + self.rulingExtent = 0 for rulingIndex in xrange( 1, int( math.ceil( self.halfCenterModel / self.rulingSeparationWidthMillimeters ) ) ): modelDistance = rulingIndex * self.rulingSeparationWidthMillimeters - self.negativeRulings.append( Ruling( modelDistance, self.getRoundedRulingText( 1, - modelDistance ) ) ) - self.positiveRulings.append( Ruling( modelDistance, self.getRoundedRulingText( 1, modelDistance ) ) ) - self.rulingExtentHalf = 0.5 * self.rulingExtent + self.val = self.getRoundedRulingText( 1, - modelDistance ) + self.negativeRulings.append( Ruling( modelDistance, self.val ) ) + self.rulingExtent = max(self.rulingExtent, self.val) + self.val = self.getRoundedRulingText( 1, modelDistance ) + self.positiveRulings.append( Ruling( modelDistance, self.val ) ) + self.rulingExtent = max(self.rulingExtent, self.val) + self.rulingExtentHalf = self.rulingExtent + self.rulingExtent = 2 * self.rulingExtent def drawRuling( self, projectiveSpace, relativeRulingEnd, ruling, tags, viewBegin, viewEnd ): "Draw ruling." @@ -840,6 +851,16 @@ def getScreenView( self, point, projectiveSpace ): "Get the point in screen view perspective." return self.getScreenComplex( projectiveSpace.getDotComplex(point) ) + def digits(self, val): + "Convert (float) val to a reasonably short string" + if abs(val) >= 10.0: + return str(int(val)) + if abs(val) > 0.1: + return str.format('{:.1f}', val) + if val == 0.0: + return '0' + return str.format('{:.2f}', val) + def printHexadecimalColorName(self, name): "Print the color name in hexadecimal." colorTuple = self.canvas.winfo_rgb( name ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/skeinlayer.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/skeinlayer.py index 484554063..f662e04d6 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/skeinlayer.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/skeinlayer.py @@ -74,6 +74,11 @@ The zoom in mouse tool will zoom in the display at the point where the mouse was clicked, increasing the scale by a factor of two. The zoom out tool will zoom out the display at the point where the mouse was clicked, decreasing the scale by a factor of two. +===Font scale factor=== +This is needed to adjust for the ratio between the numbers +reported by font.measure() and the pixel density of the monitor. +Unfortunately there seems to be no reliable way of calculating it. + ===Screen Inset=== ====Screen Horizontal Inset==== Default is one hundred. @@ -144,6 +149,8 @@ from skeinforge_application.skeinforge_utilities import skeinforge_profile import os import sys +import Tkinter +import tkFont __author__ = 'Enrique Perez (perez_enrique@yahoo.com)' __date__ = '$Date: 2008/21/04 $' @@ -177,15 +184,11 @@ def getWindowGivenTextRepository( fileName, gcodeText, repository ): "Display a gcode file in a skeinlayer window given the text and settings." skein = SkeinlayerSkein() skein.parseGcode( fileName, gcodeText, repository ) + print('') return SkeinWindow( repository, skein ) def writeOutput(fileName, fileNamePenultimate, fileNameSuffix, filePenultimateWritten, gcodeText=''): "Display a skeinlayered gcode file for a skeinforge gcode file, if 'Activate Skeinlayer' is selected." - try: - import Tkinter - except: - print('Warning, skeinlayer will do nothing because Tkinter is not installed.') - return repository = settings.getReadRepository( SkeinlayerRepository() ) if repository.activateSkeinlayer.value: gcodeText = archive.getTextIfEmpty( fileNameSuffix, gcodeText ) @@ -199,7 +202,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.skeinlayer.html', self) self.baseNameSynonym = 'skeinview.csv' self.fileNameInput = settings.FileNameInput().getFromFileName( [ ('Gcode text files', '*.gcode') ], 'Open File for Skeinlayer', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Skeinlayer') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.analyze_plugins.skeinlayer.html') self.activateSkeinlayer = settings.BooleanSetting().getFromValue('Activate Skeinlayer', self, True ) self.addAnimation() self.drawArrows = settings.BooleanSetting().getFromValue('Draw Arrows', self, True ) @@ -367,10 +370,13 @@ def parseLine(self, line): self.linearMove(line, location) self.oldLocation = location - -class SkeinWindow( tableau.TableauWindow ): +class SkeinWindow( tableau.TableauWindow): def __init__(self, repository, skein): "Initialize the skein window.setWindowNewMouseTool" + self.sizedfont = tkFont.nametofont('TkDefaultFont').copy() + self.skein = skein + self.screenSize = skein.screenSize + self.setrulingExtent(repository.pixelmagic.value) self.addCanvasMenuRootScrollSkein(repository, skein, '_skeinlayer', 'Skeinlayer') horizontalRulerBoundingBox = (0, 0, int( skein.screenSize.real ), self.rulingExtent) self.horizontalRulerCanvas = settings.Tkinter.Canvas(self.root, width = self.canvasWidth, height = self.rulingExtent, scrollregion=horizontalRulerBoundingBox) @@ -381,10 +387,10 @@ def __init__(self, repository, skein): self.verticalRulerCanvas.grid(row=2, rowspan=96, column=1, sticky=settings.Tkinter.N+settings.Tkinter.S) self.verticalRulerCanvas['yscrollcommand'] = self.yScrollbar.set self.xStringVar = settings.Tkinter.StringVar(self.root) - self.xLabel = settings.Tkinter.Label(self.root, textvariable=self.xStringVar) + self.xLabel = settings.Tkinter.Label(self.root, textvariable=self.xStringVar, font = self.sizedfont) self.xLabel.grid(row=0, column=3, sticky=settings.Tkinter.W) self.yStringVar = settings.Tkinter.StringVar(self.root) - self.yLabel = settings.Tkinter.Label(self.root, textvariable=self.yStringVar) + self.yLabel = settings.Tkinter.Label(self.root, textvariable=self.yStringVar, font = self.sizedfont) self.yLabel.grid(row=0, column=4, sticky=settings.Tkinter.W) self.setWindowNewMouseTool(display_line.getNewMouseTool, repository.displayLine) self.setWindowNewMouseTool(view_move.getNewMouseTool, repository.viewMove) @@ -397,7 +403,7 @@ def addHorizontalRulerRuling( self, xMillimeters ): "Add a ruling to the horizontal ruler." xPixel = self.skein.getScreenCoordinates( complex( xMillimeters, 0.0 ) ).real self.createVerticalLine( 0.0, xPixel ) - self.horizontalRulerCanvas.create_text( xPixel + 2, 0, anchor = settings.Tkinter.NW, text = self.getRoundedRulingText( 1, xMillimeters ) ) + self.horizontalRulerCanvas.create_text( xPixel + 2, 0, anchor = settings.Tkinter.NW, text = self.digits(xMillimeters ), font = self.sizedfont ) cumulativeDistance = xMillimeters self.createVerticalLine( self.rulingExtentTiny, self.skein.getScreenCoordinates( complex( xMillimeters + self.separationWidthMillimetersTenth, 0.0 ) ).real ) for subRulingIndex in xrange(4): @@ -407,28 +413,18 @@ def addHorizontalRulerRuling( self, xMillimeters ): def addVerticalRulerRuling( self, yMillimeters ): "Add a ruling to the vertical ruler." - fontHeight = 12 yPixel = self.skein.getScreenCoordinates( complex( 0.0, yMillimeters ) ).imag self.createHorizontalLine( 0.0, yPixel ) yPixel += 2 - roundedRulingText = self.getRoundedRulingText( 1, yMillimeters ) - effectiveRulingTextLength = len( roundedRulingText ) - if roundedRulingText.find('.') != - 1: - effectiveRulingTextLength -= 1 + roundedRulingText = self.digits(yMillimeters ) + effectiveRulingTextLength = self.rulingExtent cumulativeDistance = yMillimeters self.createHorizontalLine( self.rulingExtentTiny, self.skein.getScreenCoordinates( complex( 0.0, yMillimeters + self.separationWidthMillimetersTenth ) ).imag ) for subRulingIndex in xrange(4): cumulativeDistance += self.separationWidthMillimetersFifth self.createHorizontalLine( self.rulingExtentShort, self.skein.getScreenCoordinates( complex( 0.0, cumulativeDistance ) ).imag ) self.createHorizontalLine( self.rulingExtentTiny, self.skein.getScreenCoordinates( complex( 0.0, cumulativeDistance + self.separationWidthMillimetersTenth ) ).imag ) - if effectiveRulingTextLength < 4: - self.verticalRulerCanvas.create_text( 0, yPixel, anchor = settings.Tkinter.NW, text = roundedRulingText ) - return - for character in roundedRulingText: - if character == '.': - yPixel -= fontHeight * 2 / 3 - self.verticalRulerCanvas.create_text( 0, yPixel, anchor = settings.Tkinter.NW, text = character ) - yPixel += fontHeight + self.verticalRulerCanvas.create_text( 0, yPixel, anchor = settings.Tkinter.NW, text = roundedRulingText, font = self.sizedfont ) def createHorizontalLine( self, begin, yPixel ): "Create a horizontal line for the horizontal ruler." @@ -547,6 +543,28 @@ def relayXview( self, *args ): self.canvas.xview( *args ) self.horizontalRulerCanvas.xview( *args ) + def digits(self, val): + "Convert (float) val to a reasonably short string" + if abs(val) >= 10.0: + return str(int(val)) + if abs(val) > 0.1: + return str.format('{:.1f}', val) + if val == 0.0: + return '0' + return str.format('{:.2f}', val) + + def setrulingExtent(self, pixelmagic): + "Work out self.rulingExtent from image boundbox" + val = abs(self.skein.cornerMinimumComplex.real) + length = self.sizedfont.measure(self.digits(val)) + val = abs(self.skein.cornerMaximumComplex.real) + length = max(self.sizedfont.measure(self.digits(val)), length) + val = abs(self.skein.cornerMinimumComplex.imag) + length = max(self.sizedfont.measure(self.digits(val)), length) + val = abs(self.skein.cornerMaximumComplex.imag) + length = max(self.sizedfont.measure(self.digits(val)), length) + self.rulingExtent = int(length * pixelmagic) + def relayYview( self, *args ): "Relay yview changes." self.canvas.yview( *args ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/statistic.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/statistic.py index c33615b94..4d77d1c02 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/statistic.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/statistic.py @@ -151,7 +151,7 @@ class StatisticRepository: def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.statistic.html', self) - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Statistic') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.analyze_plugins.statistic.html') self.activateStatistic = settings.BooleanSetting().getFromValue('Activate Statistic', self, True ) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Cost -', self ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/synopsis.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/synopsis.py index 220478ebb..9015a9a57 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/synopsis.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/synopsis.py @@ -181,7 +181,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.synopsis.html', self ) self.activateSynopsis = settings.BooleanSetting().getFromValue('Activate Synopsis', self, False ) self.fileNameInput = settings.FileNameInput().getFromFileName( [ ('Gcode text files', '*.gcode') ], 'Open File to Write Synopsis for', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Synopsis') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.analyze_plugins.synopsis.html') self.exportProfileAsCSVFile = settings.BooleanSetting().getFromValue('Export Profile As CSV File', self, True) self.exportProfileAsZipFile = settings.BooleanSetting().getFromValue('Export Profile As Zip File', self, False) self.executeTitle = 'Synopsis' diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/vectorwrite.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/vectorwrite.py index 5abdfd93a..aa7b70a6d 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/vectorwrite.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/analyze_plugins/vectorwrite.py @@ -202,7 +202,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.vectorwrite.html', self ) self.activateVectorwrite = settings.BooleanSetting().getFromValue('Activate Vectorwrite', self, False ) self.fileNameInput = settings.FileNameInput().getFromFileName( [ ('Gcode text files', '*.gcode') ], 'Open File to Write Vector Graphics for', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Vectorwrite') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.analyze_plugins.vectorwrite.html') self.addLayerTemplateToSVG = settings.BooleanSetting().getFromValue('Add Layer Template to SVG', self, True) self.addLoops = settings.BooleanSetting().getFromValue('Add Loops', self, True) self.addPaths = settings.BooleanSetting().getFromValue('Add Paths', self, True) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/alteration.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/alteration.py index be5eb4fa0..a14d2b3b8 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/alteration.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/alteration.py @@ -83,7 +83,9 @@ from skeinforge_application.skeinforge_utilities import skeinforge_polyfile from skeinforge_application.skeinforge_utilities import skeinforge_profile import cStringIO +import os import sys +import time __author__ = 'Enrique Perez (perez_enrique@yahoo.com)' @@ -93,7 +95,8 @@ def getCraftedText(fileName, text='', repository=None): 'Alteration a gcode linear move text.' - return getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository) + preamble = '(generated from file ' + fileName + ' )\n' + return preamble + getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository) def getCraftedTextFromText(gcodeText, repository=None): 'Alteration a gcode linear move text.' @@ -145,7 +148,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.alteration.html', self ) self.baseNameSynonym = 'bookend.csv' self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Alteration', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Alteration') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.alteration.html') self.activateAlteration = settings.BooleanSetting().getFromValue('Activate Alteration', self, True) self.nameOfEndFile = settings.StringSetting().getFromValue('Name of End File:', self, 'end.gcode') self.nameOfStartFile = settings.StringSetting().getFromValue('Name of Start File:', self, 'start.gcode') @@ -178,11 +181,14 @@ def getCraftedGcode(self, gcodeText, repository): self.lines = archive.getTextLines(gcodeText) if repository.replaceVariableWithSetting.value: self.setSettingDictionary() + self.distanceFeedRate.addLine('(generated ' + time.ctime() + ' using profile ' + os.path.basename(archive.globalTemporarySettingsPath) + ')') + print('Using start file ' + repository.nameOfStartFile.value) self.addFromUpperLowerFile(repository.nameOfStartFile.value) # Add a start file if it exists. self.parseInitialization() for self.lineIndex in xrange(self.lineIndex, len(self.lines)): line = self.lines[self.lineIndex] self.distanceFeedRate.addLine(line) + print('Using end file ' + repository.nameOfEndFile.value) self.addFromUpperLowerFile(repository.nameOfEndFile.value) # Add an end file if it exists. gcodeText = self.getReplacedAlterationText() if repository.removeRedundantMcode.value: diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/bottom.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/bottom.py index 25e02ba52..feb5c9a2c 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/bottom.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/bottom.py @@ -99,7 +99,7 @@ def __init__(self): 'skeinforge_application.skeinforge_plugins.craft_plugins.bottom.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Bottom', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Bottom') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.bottom.html') self.activateBottom = settings.BooleanSetting().getFromValue('Activate Bottom', self, True) self.additionalHeightOverLayerThickness = settings.FloatSpin().getFromValue( 0.0, 'Additional Height over Layer Thickness (ratio):', self, 1.0, 0.5) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/carve.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/carve.py index 45873eadd..23ee2b002 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/carve.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/carve.py @@ -159,7 +159,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.carve.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getTranslatorFileTypeTuples(), 'Open File for Carve', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Carve') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.carve.html') self.addLayerTemplateToSVG = settings.BooleanSetting().getFromValue('Add Layer Template to SVG', self, True) self.edgeWidthOverHeight = settings.FloatSpin().getFromValue( 1.4, 'Edge Width over Height (ratio):', self, 2.2, 1.8 ) self.extraDecimalPlaces = settings.FloatSpin().getFromValue(0.0, 'Extra Decimal Places (float):', self, 3.0, 2.0) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/chamber.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/chamber.py index ed394197a..c35188872 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/chamber.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/chamber.py @@ -207,7 +207,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.chamber.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Chamber', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Chamber') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.chamber.html') self.activateChamber = settings.BooleanSetting().getFromValue('Activate Chamber', self, True ) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Bed -', self ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/clip.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/clip.py index 56e29fb8a..3aa15a187 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/clip.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/clip.py @@ -91,7 +91,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.clip.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Clip', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Clip') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.clip.html') self.activateClip = settings.BooleanSetting().getFromValue('Activate Clip', self, True) self.clipOverEdgeWidth = settings.FloatSpin().getFromValue(0.1, 'Clip Over Perimeter Width (ratio):', self, 0.8, 0.5) self.maximumConnectionDistanceOverEdgeWidth = settings.FloatSpin().getFromValue(1.0, 'Maximum Connection Distance Over Perimeter Width (ratio):', self, 20.0, 10.0) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/comb.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/comb.py index 0e7a26a19..cb417d790 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/comb.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/comb.py @@ -162,7 +162,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.comb.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Comb', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Comb') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.comb.html') self.activateComb = settings.BooleanSetting().getFromValue('Activate Comb', self, False ) self.runningJumpSpace = settings.FloatSpin().getFromValue(0.0, 'Running Jump Space (mm):', self, 5.0, 2.0) self.executeTitle = 'Comb' diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/cool.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/cool.py index da871f2b9..6d465b380 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/cool.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/cool.py @@ -141,8 +141,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.cool.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Cool', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute( - 'http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Cool') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.cool.html') self.activateCool = settings.BooleanSetting().getFromValue('Activate Cool', self, True) self.bridgeCool = settings.FloatSpin().getFromValue(0.0, 'Bridge Cool (Celcius):', self, 10.0, 1.0) self.coolType = settings.MenuButtonDisplay().getFromName('Cool Type:', self) @@ -337,7 +336,10 @@ def parseInitialization(self): elif firstWord == '(': self.oldFlowRate = float(splitLine[1]) elif firstWord == '(': - self.orbitalFeedRatePerSecond = float(splitLine[1]) + if float(splitLine[1]) == 0.0: + self.orbitalFeedRatePerSecond = 2.01 + else: + self.orbitalFeedRatePerSecond = float(splitLine[1]) self.distanceFeedRate.addLine(line) def parseLine(self, line): diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/dimension.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/dimension.py index 6a9944ca5..cc59c091c 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/dimension.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/dimension.py @@ -62,6 +62,11 @@ Defines the minimum distance that the extruder head has to travel from the end of one thread to the beginning of another, in order to trigger the extruder retraction. Setting this to a high value means the extruder will retract only occasionally, setting it to a low value means the extruder will retract most of the time. +===Z Distance Multiplier=== +Default: 10 + +Defines the multiplier that is applied to the Z distance when calculating a distance to compare with the Minimum Travel for Retraction. This is set to a large value to force Filament Retraction before a layer change. Dual Extrusion inserts tool switches on a layer change, so this should prevent filament oozing out of the extruder which is currently inactive. It can be set to 1 if you never use Dual Extrusion. + ===Retract Within Island=== Default is off. @@ -147,7 +152,8 @@ def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.dimension.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Dimension', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Dimension') + #self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Dimension') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.dimension.html') self.activateDimension = settings.BooleanSetting().getFromValue('Activate Dimension', self, False ) extrusionDistanceFormatLatentStringVar = settings.LatentStringVar() self.extrusionDistanceFormatChoiceLabel = settings.LabelDisplay().getFromName('Extrusion Distance Format Choice: ', self ) @@ -161,9 +167,10 @@ def __init__(self): settings.LabelSeparator().getFromRepository(self) self.maximumEValueBeforeReset = settings.FloatSpin().getFromValue(0.0, 'Maximum E Value before Reset (float):', self, 999999.9, 91234.0) self.minimumTravelForRetraction = settings.FloatSpin().getFromValue(0.0, 'Minimum Travel for Retraction (millimeters):', self, 2.0, 1.0) + self.zDistanceRatio = settings.FloatSpin().getFromValue( 1.0, 'Z Distance Multiplier:', self, 20.0, 10.0 ) self.retractWithinIsland = settings.BooleanSetting().getFromValue('Retract Within Island', self, False) - self.retractionDistance = settings.FloatSpin().getFromValue( 0.0, 'Retraction Distance (millimeters):', self, 100.0, 0.0 ) - self.restartExtraDistance = settings.FloatSpin().getFromValue( 0.0, 'Restart Extra Distance (millimeters):', self, 100.0, 0.0 ) + self.retractionDistance = settings.FloatSpin().getFromValue( 0.0, 'Retraction Distance (millimeters):', self, 10.0, 0.0 ) + self.restartExtraDistance = settings.FloatSpin().getFromValue( 0.0, 'Restart Extra Distance (millimeters):', self, 10.0, 0.0 ) self.executeTitle = 'Dimension' def execute(self): @@ -190,7 +197,8 @@ def __init__(self): self.retractionRatio = 1.0 self.totalExtrusionDistance = 0.0 self.travelFeedRatePerSecond = None - self.zDistanceRatio = 5.0 + self.zDistanceRatio = 10.0 + self.EarlyShutdownActive = False def addLinearMoveExtrusionDistanceLine(self, extrusionDistance): 'Get the extrusion distance string from the extrusion distance.' @@ -216,8 +224,7 @@ def getCraftedGcode(self, gcodeText, repository): return gcodeText self.restartDistance = self.repository.retractionDistance.value + self.repository.restartExtraDistance.value self.extruderRetractionSpeedMinuteString = self.distanceFeedRate.getRounded(60.0 * self.repository.extruderRetractionSpeed.value) - if self.maximumZFeedRatePerSecond != None and self.travelFeedRatePerSecond != None: - self.zDistanceRatio = self.travelFeedRatePerSecond / self.maximumZFeedRatePerSecond + self.firstMove = True for lineIndex in xrange(self.lineIndex, len(self.lines)): self.parseLine( lineIndex ) return self.distanceFeedRate.output.getvalue() @@ -383,15 +390,26 @@ def parseLine( self, lineIndex ): self.layerIndex += 1 settings.printProgress(self.layerIndex, 'dimension') elif firstWord == 'M101': - self.addLinearMoveExtrusionDistanceLine(self.restartDistance * self.retractionRatio) + if not self.firstMove: + self.addLinearMoveExtrusionDistanceLine(self.restartDistance * self.retractionRatio) + self.firstMove = False if self.totalExtrusionDistance > self.repository.maximumEValueBeforeReset.value: if not self.repository.relativeExtrusionDistance.value: self.distanceFeedRate.addLine('G92 E0') self.totalExtrusionDistance = 0.0 self.isExtruderActive = True - elif firstWord == 'M103': + elif firstWord == '()': + self.EarlyShutdownActive = True + elif firstWord == 'M103' and not self.EarlyShutdownActive: + self.retractionRatio = self.getRetractionRatio(lineIndex) + self.addLinearMoveExtrusionDistanceLine(-self.repository.retractionDistance.value * self.retractionRatio) + self.isExtruderActive = False + elif firstWord == '()': + self.EarlyShutdownActive = False self.retractionRatio = self.getRetractionRatio(lineIndex) + self.distanceFeedRate.addLine('M101') self.addLinearMoveExtrusionDistanceLine(-self.repository.retractionDistance.value * self.retractionRatio) + self.distanceFeedRate.addLine('M103') self.isExtruderActive = False elif firstWord == 'M108': self.flowRate = float( splitLine[1][1 :] ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/dwindle.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/dwindle.py index 8f175ea4c..196cd2c68 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/dwindle.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/dwindle.py @@ -95,7 +95,7 @@ def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.dwindle.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Dwindle', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Dwindle') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.dwindle.html') self.activateDwindle = settings.BooleanSetting().getFromValue('Activate Dwindle', self, False) settings.LabelSeparator().getFromRepository(self) self.endRateMultiplier = settings.FloatSpin().getFromValue(0.4, 'End Rate Multiplier (ratio):', self, 0.8, 0.5) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/export.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/export.py index 9b2d552e1..1c4cd32e1 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/export.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/export.py @@ -52,20 +52,61 @@ When selected, the penultimate gcode will be sent to the analyze plugins to be analyzed and viewed. -===Comment Choice=== -Default is 'Delete All Comments'. +===Comment Deletion Choices=== +These checkboxes determine which comments, if any, will be removed from the exported gcode. Note they are honoured in the order given, so that for example if Delete Comments is unchecked (the default), then comments will not be deleted regardless of the subsequent settings. -====Do Not Delete Comments==== -When selected, export will not delete comments. Crafting comments slow down the processing in many firmware types, which leads to pauses and therefore a lower quality print. - -====Delete Crafting Comments==== -When selected, export will delete the time consuming crafting comments, but leave the initialization comments. Since the crafting comments are deleted, there are no pauses during extrusion. The remaining initialization comments provide some useful information for the analyze tools. +====Delete Comments==== +Default is unchecked. + +If checked, any preface comments starting with are removed. The code as shipped does not generate any comments, but user modifications may add some. They can be useful for recording information like the profile or version used to generate the gcode, if other comments are being deleted. + +====Delete Trace Comments==== +Default is unchecked. + +If checked, any preface comments starting with are removed. The code as shipped does not generate any comments, but there is a debugging aid which adds some. + +====Delete Comments==== +Default is unchecked. + +If checked, any comments starting with are removed. The Dual Extrusion gcode merge logic requires the comments to be left in, so this box should normally remain unchecked unless you have a single extruder printer and never use Dual Extrusion. + +====Delete Settings Comments==== +Default is unchecked. + +If checked, the block of comments near the start of the gcode reporting the settings used are removed. + +====Delete Other Initialisation Comments==== +Default is unchecked. + +If checked, the block of comments near the start of the gcode between () and (), apart from any described above, are removed. + +====Delete Other Preface Comments==== +Default is unchecked. + +If checked, any preface comments [before ()] not mentioned above are removed. If Alteration is not enabled, all comments are preface comments. + +====Delete Other Crafting Comments==== +Default is unchecked. + +If checked, all comments between () and (), other than those described above, are removed. You will usually not want these unless you are debugging the gcode generator. + +====Delete Other Tagged Comments==== +Default is False. + +If checked, all comments starting with '(<', other than those described above, are removed. + +====Delete Other Starred Comments==== +Default is False. + +If checked, all comments starting with '(*', other than those described above, are removed. -====Delete All Comments==== -When selected, export will delete all comments. The comments are not necessary to run a fabricator. Some printers do not support comments at all so the safest way is choose this option. +====Delete All Other Comments==== +Default is False. + +If checked, all comments other than those described above are removed. ===Export Operations=== -Export presents the user with a choice of the export plugins in the export_plugins folder. The chosen plugin will then modify the gcode or translate it into another format. There is also the "Do Not Change Output" choice, which will not change the output. An export plugin is a script in the export_plugins folder which has the getOutput function, the globalIsReplaceable variable and if it's output is not replaceable, the writeOutput function. +Export presents the user with a choice of the export plugins in the export_plugins folder. The chosen plugin will then modify the gcode or translate it into another format. There is also the "Do Not Change Output" choice, which will not change the output. An export plugin is a script in the export_plugins folder which has the getOutput function, the globalIsReplaceable variable and if its output is not replaceable, the writeOutput function. ===File Extension=== Default is gcode. @@ -215,7 +256,7 @@ def getReplaceableExportGcode(nameOfReplaceFile, replaceableExportGcode): if len(replaceLines) < 1: return replaceableExportGcode for replaceLine in replaceLines: - splitLine = replaceLine.replace('\\n', '\t').split('\t') + splitLine = replaceLine.replace('\n', '\t').split('\t') if len(splitLine) > 0: replaceableExportGcode = replaceableExportGcode.replace(splitLine[0], '\n'.join(splitLine[1 :])) output = cStringIO.StringIO() @@ -266,7 +307,8 @@ def writeOutput(fileName, shouldAnalyze=True): repository = ExportRepository() settings.getReadRepository(repository) startTime = time.time() - print('File ' + archive.getSummarizedFileName(fileName) + ' is being chain exported.') + summarisedFileName = archive.getSummarizedFileName(fileName) + print('File ' + summarisedFileName + ' is being chain exported.') fileNameSuffix = fileName[: fileName.rfind('.')] if repository.addExportSuffix.value: fileNameSuffix += '_export' @@ -319,7 +361,7 @@ def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.export.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Export', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Export') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.export.html') self.activateExport = settings.BooleanSetting().getFromValue('Activate Export', self, True) self.addDescriptiveExtension = settings.BooleanSetting().getFromValue('Add Descriptive Extension', self, False) self.addExportSuffix = settings.BooleanSetting().getFromValue('Add Export Suffix', self, True) @@ -327,10 +369,17 @@ def __init__(self): self.addTimestampExtension = settings.BooleanSetting().getFromValue('Add Timestamp Extension', self, False) self.alsoSendOutputTo = settings.StringSetting().getFromValue('Also Send Output To:', self, '') self.analyzeGcode = settings.BooleanSetting().getFromValue('Analyze Gcode', self, True) - self.commentChoice = settings.MenuButtonDisplay().getFromName('Comment Choice:', self) - self.doNotDeleteComments = settings.MenuRadio().getFromMenuButtonDisplay(self.commentChoice, 'Do Not Delete Comments', self, False) - self.deleteCraftingComments = settings.MenuRadio().getFromMenuButtonDisplay(self.commentChoice, 'Delete Crafting Comments', self, False) - self.deleteAllComments = settings.MenuRadio().getFromMenuButtonDisplay(self.commentChoice, 'Delete All Comments', self, True) + self.commentLabel = settings.LabelDisplay().getFromName('Comment Deletion Choices:', self) + self.deleteKeepComments = settings.BooleanSetting().getFromValue('Delete Comments', self, False) + self.deleteTraceComments = settings.BooleanSetting().getFromValue('Delete Trace Comments', self, False) + self.deleteLayerComments = settings.BooleanSetting().getFromValue('Delete Comments', self, False) + self.deleteSettingsComments = settings.BooleanSetting().getFromValue('Delete Settings Comments', self, False) + self.deleteInitialisationComments = settings.BooleanSetting().getFromValue('Delete Other Initialisation Comments', self, False) + self.deletePrefaceComments = settings.BooleanSetting().getFromValue('Delete Other Preface Comments', self, False) + self.deleteCraftingComments = settings.BooleanSetting().getFromValue('Delete Other Crafting Comments', self, False) + self.deleteTaggedComments = settings.BooleanSetting().getFromValue('Delete Other Tagged Comments', self, False) + self.deleteStarredComments = settings.BooleanSetting().getFromValue('Delete Other Starred Comments', self, False) + self.deleteOtherComments = settings.BooleanSetting().getFromValue('Delete All Other Comments', self, False) exportPluginsFolderPath = archive.getAbsoluteFrozenFolderPath(archive.getCraftPluginsDirectoryPath('export.py'), 'export_plugins') exportStaticDirectoryPath = os.path.join(exportPluginsFolderPath, 'static_plugins') exportPluginFileNames = archive.getPluginFileNamesFromDirectoryPath(exportPluginsFolderPath) @@ -378,6 +427,9 @@ def addLine(self, line): def getCraftedGcode( self, repository, gcodeText ): 'Parse gcode text and store the export gcode.' self.repository = repository + self.inPreface = True + self.inInitialisation = False + self.crafting = False lines = archive.getTextLines(gcodeText) for line in lines: self.parseLine(line) @@ -397,19 +449,65 @@ def parseLine(self, line): if len(splitLine) < 1: return firstWord = splitLine[0] + if firstWord == '()': + self.inPreface = False + if firstWord == '()': + self.crafting = True + if not self.repository.deleteCraftingComments.value: + self.addLine(line) + return if firstWord == '()': self.crafting = False - elif firstWord == '(': + if not self.repository.deleteCraftingComments.value: + self.addLine(line) + return + if firstWord == '(': self.decimalPlacesExported = int(splitLine[1]) - 1 - if self.repository.deleteAllComments.value or (self.repository.deleteCraftingComments.value and self.crafting): - if firstWord[0] == '(': - return - else: - line = line.split(';')[0].split('(')[0].strip() - if firstWord == '()': - self.crafting = True + if firstWord == '(': + if not self.repository.deleteKeepComments.value: + self.addLine(line) + return + if firstWord == '(' or firstWord.find('(') == 0: + if not self.repository.deleteLayerComments.value: + self.addLine(line) + return + if firstWord == '(': + if not self.repository.deleteTraceComments.value: + self.addLine(line) + return + if firstWord == '()' or firstWord == '(' or firstWord == '()': + if not self.repository.deleteSettingsComments.value: + self.addLine(line) + return + if firstWord == '()': + self.inInitialisation = True + if not self.repository.deleteInitialisationComments.value: + self.addLine(line) + return if firstWord == '()': - self.addLine(gcodec.getTagBracketedProcedure('export')) + self.inInitialisation = False + if not self.repository.deleteInitialisationComments.value: + self.addLine(gcodec.getTagBracketedProcedure('export')) + self.addLine(line) + return + if firstWord[0] == '(': + if self.inPreface: + if self.repository.deletePrefaceComments.value: + return + elif self.inInitialisation: + if self.repository.deleteInitialisationComments.value: + return + elif firstWord[1] == '<': + if self.crafting: + if self.repository.deleteCraftingComments.value: + return + elif self.repository.deleteTaggedComments.value: + return + elif firstWord[1] == '*': + if self.repository.deleteStarredComments.value: + return + elif self.repository.deleteOtherComments.value: + return if firstWord != 'G1' and firstWord != 'G2' and firstWord != 'G3' : self.addLine(line) return diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/fill.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/fill.py index 7f985fddf..1c609c6ad 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/fill.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/fill.py @@ -774,7 +774,7 @@ def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.fill.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Fill', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Fill') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.fill.html') self.activateFill = settings.BooleanSetting().getFromValue('Activate Fill', self, True) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Diaphragm -', self ) @@ -867,6 +867,12 @@ def addFill(self, layerIndex): self.isJunctionWide = True surroundingCarves = [] self.distanceFeedRate.addLine('( %s )' % rotatedLayer.z) + if layerIndex == 0: + self.distanceFeedRate.addLine('()M104' + + ' S') + else: + self.distanceFeedRate.addLine('()M104' + + ' S') if layerRemainder >= int(round(self.repository.diaphragmThickness.value)): for surroundingIndex in xrange(1, self.solidSurfaceThickness + 1): self.addRotatedCarve(layerIndex, -surroundingIndex, reverseRotation, surroundingCarves) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/fillet.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/fillet.py index d5af827ed..78d572560 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/fillet.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/fillet.py @@ -361,7 +361,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.fillet.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File to be Filleted', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Fillet') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.fillet.html') self.activateFillet = settings.BooleanSetting().getFromValue('Activate Fillet', self, False ) self.filletProcedureChoiceLabel = settings.LabelDisplay().getFromName('Fillet Procedure Choice: ', self ) filletLatentStringVar = settings.LatentStringVar() diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/home.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/home.py index 6048d6194..b3ac1551f 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/home.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/home.py @@ -81,7 +81,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.home.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Home', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Home') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.home.html') self.activateHome = settings.BooleanSetting().getFromValue('Activate Home', self, True ) self.nameOfHomeFile = settings.StringSetting().getFromValue('Name of Home File:', self, 'home.gcode') self.executeTitle = 'Home' diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/hop.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/hop.py index 9b4ac36c3..95ad03edb 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/hop.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/hop.py @@ -92,7 +92,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.hop.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Hop', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Hop') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.hop.html') self.activateHop = settings.BooleanSetting().getFromValue('Activate Hop', self, False ) self.hopOverLayerThickness = settings.FloatSpin().getFromValue( 0.5, 'Hop Over Layer Thickness (ratio):', self, 1.5, 1.0 ) self.minimumHopAngle = settings.FloatSpin().getFromValue( 20.0, 'Minimum Hop Angle (degrees):', self, 60.0, 30.0 ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/inset.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/inset.py index bb68db20e..04734fc80 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/inset.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/inset.py @@ -298,7 +298,7 @@ def __init__(self): 'Infill in Direction of Bridge' : 'carve.csv', 'Infill Width over Thickness (ratio):' : 'fill.csv'} self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Inset', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Inset') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.inset.html') self.addCustomCodeForTemperatureReading = settings.BooleanSetting().getFromValue('Add Custom Code for Temperature Reading', self, True) self.infillInDirectionOfBridge = settings.BooleanSetting().getFromValue('Infill in Direction of Bridge', self, True) self.infillWidthOverThickness = settings.FloatSpin().getFromValue(1.3, 'Infill Width over Thickness (ratio):', self, 1.7, 1.5) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/jitter.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/jitter.py index df269c898..8dc7b22d2 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/jitter.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/jitter.py @@ -115,7 +115,7 @@ def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.jitter.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Jitter', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Jitter') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.jitter.html') self.activateJitter = settings.BooleanSetting().getFromValue('Activate Jitter', self, True) self.jitterOverEdgeWidth = settings.FloatSpin().getFromValue(1.0, 'Jitter Over Perimeter Width (ratio):', self, 3.0, 2.0) self.executeTitle = 'Jitter' diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/lash.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/lash.py index 9843d43d7..d92cca6ac 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/lash.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/lash.py @@ -87,7 +87,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.lash.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Lash', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Lash') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.lash.html') self.activateLash = settings.BooleanSetting().getFromValue('Activate Lash', self, False ) self.xBacklash = settings.FloatSpin().getFromValue( 0.1, 'X Backlash (mm):', self, 0.5, 0.2 ) self.yBacklash = settings.FloatSpin().getFromValue( 0.1, 'Y Backlash (mm):', self, 0.5, 0.3 ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/limit.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/limit.py index 3589e52df..04f6a8619 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/limit.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/limit.py @@ -85,7 +85,7 @@ def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.limit.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Limit', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Limit') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.limit.html') self.activateLimit = settings.BooleanSetting().getFromValue('Activate Limit', self, True) self.maximumInitialFeedRate = settings.FloatSpin().getFromValue(0.5, 'Maximum Initial Feed Rate (mm/s):', self, 10.0, 1.0) self.executeTitle = 'Limit' diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/multiply.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/multiply.py index 44c7fb72f..3e7402115 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/multiply.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/multiply.py @@ -111,7 +111,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.multiply.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Multiply', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Multiply') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.multiply.html') self.activateMultiply = settings.BooleanSetting().getFromValue('Activate Multiply', self, False) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Center -', self ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/oozebane.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/oozebane.py index 234b85f8c..96f488d75 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/oozebane.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/oozebane.py @@ -116,7 +116,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.oozebane.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Oozebane', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Oozebane') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.oozebane.html') self.activateOozebane = settings.BooleanSetting().getFromValue('Activate Oozebane', self, False ) self.afterStartupDistance = settings.FloatSpin().getFromValue( 0.7, 'After Startup Distance (millimeters):', self, 1.7, 1.2 ) self.earlyShutdownDistance = settings.FloatSpin().getFromValue( 0.7, 'Early Shutdown Distance (millimeters):', self, 1.7, 1.2 ) @@ -168,11 +168,6 @@ def addAfterStartupLine( self, splitLine ): self.distanceFeedRate.addLine( self.getLinearMoveWithFeedRate( feedRate, locationBack ) ) self.startupStepIndex += 1 - def addLineSetShutdowns(self, line): - "Add a line and set the shutdown variables." - self.distanceFeedRate.addLine(line) - self.isShutdownEarly = True - def getActiveFeedRateRatio(self): "Get the feed rate of the first active move over the operating feed rate." isSearchExtruderActive = self.isExtruderActive @@ -238,7 +233,7 @@ def getAddShutSlowDownLine(self, line): shutdownFlowRateMultiplier = self.getShutdownFlowRateMultiplier( 1.0 - distanceThreadEnd / self.earlyShutdownDistance, len( self.earlyShutdownDistances ) ) line = self.getLinearMoveWithFeedRate( self.feedRateMinute * shutdownFlowRateMultiplier, location ) self.distanceFeedRate.addLine(line) - return False + return distanceThreadEnd != None segment = self.oldLocation - location segmentLength = segment.magnitude() distanceBack = self.earlyShutdownDistances[ self.shutdownStepIndex ] - distanceThreadEnd @@ -249,7 +244,9 @@ def getAddShutSlowDownLine(self, line): if not self.isCloseToEither( locationBack, location, self.oldLocation ): line = self.getLinearMoveWithFeedRate( self.feedRateMinute, locationBack ) self.distanceFeedRate.addLine(line) - self.addLineSetShutdowns('M103') + self.distanceFeedRate.addLine("()") + self.distanceFeedRate.addLine('M103') + self.isShutdownEarly = True return True if self.isClose( locationBack, self.oldLocation ): return True @@ -478,6 +475,7 @@ def parseLine(self, line): self.distanceFromThreadEndToThreadBeginning = None self.earlyStartupDistance = None if self.isShutdownEarly: + self.distanceFeedRate.addLine("()") self.isShutdownEarly = False return self.distanceFeedRate.addLine(line) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/preface.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/preface.py index f39a2609f..aab772881 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/preface.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/preface.py @@ -106,7 +106,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.preface.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Preface', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Preface') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.preface.html') self.meta = settings.StringSetting().getFromValue('Meta:', self, '') self.setPositioningToAbsolute = settings.BooleanSetting().getFromValue('Set Positioning to Absolute', self, True ) self.setUnitsToMillimeters = settings.BooleanSetting().getFromValue('Set Units to Millimeters', self, True ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/raft.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/raft.py index ec8c0aee5..4ef170763 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/raft.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/raft.py @@ -339,8 +339,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.raft.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Raft', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute( - 'http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Raft') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.raft.html') self.activateRaft = settings.BooleanSetting().getFromValue('Activate Raft', self, True) self.addRaftElevateNozzleOrbitSetAltitude = settings.BooleanSetting().getFromValue( 'Add Raft, Elevate Nozzle, Orbit:', self, True) @@ -923,7 +922,10 @@ def parseInitialization(self): elif firstWord == '(': self.objectNextLayersTemperature = float(splitLine[1]) elif firstWord == '(': - self.orbitalFeedRatePerSecond = float(splitLine[1]) + if float(splitLine[1]) == 0.0: + self.orbitalFeedRatePerSecond = 2.01 + else: + self.orbitalFeedRatePerSecond = float(splitLine[1]) elif firstWord == '(': self.operatingFeedRateMinute = 60.0 * float(splitLine[1]) self.feedRateMinute = self.operatingFeedRateMinute diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/scale.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/scale.py index c3acb7ca2..b0e1201a5 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/scale.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/scale.py @@ -107,7 +107,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.scale.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Scale', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Scale') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.scale.html') self.activateScale = settings.BooleanSetting().getFromValue('Activate Scale', self, False) self.xyPlaneScale = settings.FloatSpin().getFromValue(0.99, 'XY Plane Scale (ratio):', self, 1.03, 1.01) self.zAxisScale = settings.FloatSpin().getFromValue(0.99, 'Z Axis Scale (ratio):', self, 1.02, 1.0) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/skin.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/skin.py index d3ea4ea96..d076d9dae 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/skin.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/skin.py @@ -118,7 +118,7 @@ def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.skin.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Skin', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Skin') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.skin.html') self.activateSkin = settings.BooleanSetting().getFromValue('Activate Skin', self, False) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Division -', self) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/skirt.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/skirt.py index 21bc7d971..d8fb694ec 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/skirt.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/skirt.py @@ -130,7 +130,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.skirt.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Skirt', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Skirt') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.skirt.html') self.activateSkirt = settings.BooleanSetting().getFromValue('Activate Skirt', self, False) self.convex = settings.BooleanSetting().getFromValue('Convex:', self, True) self.gapOverEdgeWidth = settings.FloatSpin().getFromValue(1.0, 'Gap over Perimeter Width (ratio):', self, 5.0, 3.0) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/smooth.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/smooth.py index 0a386e363..61194782a 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/smooth.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/smooth.py @@ -87,7 +87,7 @@ def __init__(self): 'Set the default settings, execute title & settings fileName.' skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.smooth.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Smooth', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Smooth') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.smooth.html') self.activateSmooth = settings.BooleanSetting().getFromValue('Activate Smooth', self, False) self.layersFrom = settings.IntSpin().getSingleIncrementFromValue(0, 'Layers From (index):', self, 912345678, 1) self.maximumShorteningOverWidth = settings.FloatSpin().getFromValue(0.2, 'Maximum Shortening over Width (float):', self, 2.0, 1.2) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/speed.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/speed.py index 5ebc80662..b31e1377d 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/speed.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/speed.py @@ -172,7 +172,7 @@ def __init__(self): 'Object First Layer Flow Rate Infill Multiplier (ratio):' : 'raft.csv', 'Object First Layer Flow Rate Perimeter Multiplier (ratio):' : 'raft.csv'} self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Speed', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Speed') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.speed.html') self.activateSpeed = settings.BooleanSetting().getFromValue('Activate Speed', self, True ) self.addFlowRate = settings.BooleanSetting().getFromValue('Add Flow Rate:', self, True ) settings.LabelSeparator().getFromRepository(self) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/splodge.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/splodge.py index 7404029cf..538d812af 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/splodge.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/splodge.py @@ -106,7 +106,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.splodge.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Splodge', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Splodge') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.splodge.html') self.activateSplodge = settings.BooleanSetting().getFromValue('Activate Splodge', self, False ) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Initial -', self ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/stretch.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/stretch.py index cb82ed331..dce9cd151 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/stretch.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/stretch.py @@ -223,7 +223,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.stretch.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Stretch', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Stretch') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.stretch.html') self.activateStretch = settings.BooleanSetting().getFromValue('Activate Stretch', self, False ) self.crossLimitDistanceOverEdgeWidth = settings.FloatSpin().getFromValue( 3.0, 'Cross Limit Distance Over Perimeter Width (ratio):', self, 10.0, 5.0 ) self.loopStretchOverEdgeWidth = settings.FloatSpin().getFromValue( 0.05, 'Loop Stretch Over Perimeter Width (ratio):', self, 0.25, 0.11 ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/temperature.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/temperature.py index e031451d3..6ea0d7959 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/temperature.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/temperature.py @@ -14,48 +14,48 @@ http://bothacker.com/wp-content/uploads/2009/09/18h5m53s9.29.2009.png ====Cooling Rate==== -Default is three degrees Celcius per second. +Default is three degrees Celsius per second. Defines the cooling rate of the extruder. ====Heating Rate==== -Default is ten degrees Celcius per second. +Default is ten degrees Celsius per second. Defines the heating rate of the extruder. ===Temperature=== ====Base Temperature==== -Default for ABS is two hundred degrees Celcius. +Default for ABS is two hundred degrees Celsius. Defines the raft base temperature. ====Interface Temperature==== -Default for ABS is two hundred degrees Celcius. +Default for ABS is two hundred degrees Celsius. Defines the raft interface temperature. ====Object First Layer Infill Temperature==== -Default for ABS is 195 degrees Celcius. +Default for ABS is 195 degrees Celsius. Defines the infill temperature of the first layer of the object. ====Object First Layer Perimeter Temperature==== -Default for ABS is two hundred and twenty degrees Celcius. +Default for ABS is two hundred and twenty degrees Celsius. Defines the edge temperature of the first layer of the object. ====Object Next Layers Temperature==== -Default for ABS is two hundred and thirty degrees Celcius. +Default for ABS is two hundred and thirty degrees Celsius. Defines the temperature of the next layers of the object. ====Support Layers Temperature==== -Default for ABS is two hundred degrees Celcius. +Default for ABS is two hundred degrees Celsius. Defines the support layers temperature. ====Supported Layers Temperature==== -Default for ABS is two hundred and thirty degrees Celcius. +Default for ABS is two hundred and thirty degrees Celsius. Defines the temperature of the supported layers of the object, those layers which are right above a support layer. @@ -125,21 +125,21 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.temperature.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Temperature', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Temperature') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.temperature.html') self.activateTemperature = settings.BooleanSetting().getFromValue('Activate Temperature', self, True ) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Rate -', self ) - self.coolingRate = settings.FloatSpin().getFromValue( 1.0, 'Cooling Rate (Celcius/second):', self, 20.0, 3.0 ) - self.heatingRate = settings.FloatSpin().getFromValue( 1.0, 'Heating Rate (Celcius/second):', self, 20.0, 10.0 ) + self.coolingRate = settings.FloatSpin().getFromValue( 1.0, 'Cooling Rate (Celsius/second):', self, 20.0, 3.0 ) + self.heatingRate = settings.FloatSpin().getFromValue( 1.0, 'Heating Rate (Celsius/second):', self, 20.0, 10.0 ) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Temperature -', self ) - self.baseTemperature = settings.FloatSpin().getFromValue( 140.0, 'Base Temperature (Celcius):', self, 260.0, 200.0 ) - self.interfaceTemperature = settings.FloatSpin().getFromValue( 140.0, 'Interface Temperature (Celcius):', self, 260.0, 200.0 ) - self.objectFirstLayerInfillTemperature = settings.FloatSpin().getFromValue( 140.0, 'Object First Layer Infill Temperature (Celcius):', self, 260.0, 195.0 ) - self.objectFirstLayerPerimeterTemperature = settings.FloatSpin().getFromValue( 140.0, 'Object First Layer Perimeter Temperature (Celcius):', self, 260.0, 220.0 ) - self.objectNextLayersTemperature = settings.FloatSpin().getFromValue( 140.0, 'Object Next Layers Temperature (Celcius):', self, 260.0, 230.0 ) - self.supportLayersTemperature = settings.FloatSpin().getFromValue( 140.0, 'Support Layers Temperature (Celcius):', self, 260.0, 200.0 ) - self.supportedLayersTemperature = settings.FloatSpin().getFromValue( 140.0, 'Supported Layers Temperature (Celcius):', self, 260.0, 230.0 ) + self.baseTemperature = settings.FloatSpin().getFromValue( 140.0, 'Base Temperature (Celsius):', self, 260.0, 200.0 ) + self.interfaceTemperature = settings.FloatSpin().getFromValue( 140.0, 'Interface Temperature (Celsius):', self, 260.0, 200.0 ) + self.objectFirstLayerInfillTemperature = settings.FloatSpin().getFromValue( 140.0, 'Object First Layer Infill Temperature (Celsius):', self, 260.0, 195.0 ) + self.objectFirstLayerPerimeterTemperature = settings.FloatSpin().getFromValue( 140.0, 'Object First Layer Perimeter Temperature (Celsius):', self, 260.0, 220.0 ) + self.objectNextLayersTemperature = settings.FloatSpin().getFromValue( 140.0, 'Object Next Layers Temperature (Celsius):', self, 260.0, 230.0 ) + self.supportLayersTemperature = settings.FloatSpin().getFromValue( 140.0, 'Support Layers Temperature (Celsius):', self, 260.0, 200.0 ) + self.supportedLayersTemperature = settings.FloatSpin().getFromValue( 140.0, 'Supported Layers Temperature (Celsius):', self, 260.0, 230.0 ) self.executeTitle = 'Temperature' def execute(self): diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/tower.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/tower.py index 500ad860a..8bdfefa3f 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/tower.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/tower.py @@ -123,7 +123,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.tower.html', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Tower', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Tower') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.tower.html') self.activateTower = settings.BooleanSetting().getFromValue('Activate Tower', self, False ) self.extruderPossibleCollisionConeAngle = settings.FloatSpin().getFromValue( 40.0, 'Extruder Possible Collision Cone Angle (degrees):', self, 80.0, 60.0 ) self.maximumTowerHeight = settings.IntSpin().getFromValue( 2, 'Maximum Tower Height (layers):', self, 10, 5 ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/unpause.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/unpause.py index 1827bd478..8f4681c55 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/unpause.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/unpause.py @@ -93,7 +93,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.unpause.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Unpause', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Unpause') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.unpause.html') self.activateUnpause = settings.BooleanSetting().getFromValue('Activate Unpause', self, False ) self.delay = settings.FloatSpin().getFromValue( 2.0, 'Delay (milliseconds):', self, 42.0, 28.0 ) self.maximumSpeed = settings.FloatSpin().getFromValue( 1.1, 'Maximum Speed (ratio):', self, 1.9, 1.3 ) diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/widen.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/widen.py index cc6123768..2b36b81a3 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/widen.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/widen.py @@ -118,8 +118,7 @@ def __init__(self): skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.widen.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Widen', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute( - 'http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Widen') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.widen.html') self.activateWiden = settings.BooleanSetting().getFromValue('Activate Widen', self, False) self.widenWidthOverEdgeWidth = settings.IntSpin().getFromValue(2, 'Widen Width over Edge Width (ratio):', self, 4, 2) self.executeTitle = 'Widen' diff --git a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/wipe.py b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/wipe.py index ac662ec07..d93558cb5 100644 --- a/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/wipe.py +++ b/skein_engines/skeinforge-50/skeinforge_application/skeinforge_plugins/craft_plugins/wipe.py @@ -130,7 +130,7 @@ def __init__(self): "Set the default settings, execute title & settings fileName." skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.wipe.html', self) self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Wipe', self, '') - self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Wipe') + self.openWikiManualHelpPage = settings.HelpPage().getOpenFromDocumentationSubName('skeinforge_application.skeinforge_plugins.craft_plugins.wipe.html') self.activateWipe = settings.BooleanSetting().getFromValue('Activate Wipe', self, False) settings.LabelSeparator().getFromRepository(self) settings.LabelDisplay().getFromName('- Arrival Location -', self) diff --git a/src/replicatorg/app/Base.java b/src/replicatorg/app/Base.java index 239927a31..3edae7cac 100644 --- a/src/replicatorg/app/Base.java +++ b/src/replicatorg/app/Base.java @@ -102,12 +102,13 @@ public enum InitialOpenBehavior { /** * The version number of this edition of replicatorG. */ - public static final int VERSION = 40; + public static final int VERSION = 41; /** * The textual representation of this version (4 digits, zero padded). + * (This really should be synchronised with the version in build.xml.) */ - public static final String VERSION_NAME = String.format("%04d-Beta",VERSION); + public static final String VERSION_NAME = String.format("%04dBeta",VERSION); /** * The machine controller in use. @@ -672,10 +673,14 @@ public void run() { editor.loadMachine(machineName, autoconnect); - // show the window + // show the window ... + // The following is a horrible hack, but setLocationByPlatform + // doesn't work without it. + editor.setVisible(true); + editor.setVisible(false); + editor.setLocationByPlatform(true); editor.setVisible(true); checkDirectories(); - UpdateChecker.checkLatestVersion(editor); } }); diff --git a/src/replicatorg/app/gcode/DualStrusionConstruction.java b/src/replicatorg/app/gcode/DualStrusionConstruction.java index 03e520d94..446ab478a 100644 --- a/src/replicatorg/app/gcode/DualStrusionConstruction.java +++ b/src/replicatorg/app/gcode/DualStrusionConstruction.java @@ -1,644 +1,771 @@ -package replicatorg.app.gcode; - -import java.io.File; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import java.util.logging.Level; - -import javax.swing.JOptionPane; - -import replicatorg.app.Base; -import replicatorg.machine.model.MachineType; -import replicatorg.machine.model.ToolheadAlias; -import replicatorg.machine.model.WipeModel; -import replicatorg.model.GCodeSource; -import replicatorg.plugin.toolpath.skeinforge.SkeinforgePostProcessor; -import replicatorg.util.Point5d; - - -/** - * This class takes two existing gcode files and merges them into a single gcode that can be run on a dualstrusion printer - * - * TODO: - * some small changes to try, see what they do to the print: - * tiny hops (~1mm) - * in toolchange - get max(nextFeed, lastFeed) - * - * @author Noah Levy - * @maintained Ted - */ -public class DualStrusionConstruction -{ - - private final File leftFile, rightFile; - private final MutableGCodeSource startGCode, endGCode; - private final boolean useWipes; - private final WipeModel leftWipe; - private final WipeModel rightWipe; - private final MachineType machineType; - private MutableGCodeSource result; - - public DualStrusionConstruction(File leftFile, File rightFile, - MutableGCodeSource startSource, MutableGCodeSource endSource, - MachineType type, boolean useWipes) - { - this.leftFile = leftFile; - this.rightFile = rightFile; - this.useWipes = useWipes; - this.machineType = type; - startGCode = startSource.copy(); - endGCode = endSource.copy(); - if(useWipes) - { - leftWipe = Base.getMachineLoader().getMachineInterface().getModel().getWipeFor(ToolheadAlias.LEFT); - rightWipe = Base.getMachineLoader().getMachineInterface().getModel().getWipeFor(ToolheadAlias.RIGHT); - - if(leftWipe == null || rightWipe == null) - { - String error = "Could not find wipes for the current machine: " + - Base.getMachineLoader().getMachineInterface().getModel().toString() + ". Continuing without wipes."; - JOptionPane.showConfirmDialog(null, error, - "Could not find wipes!", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE); - - useWipes = false; - } - } - else - { - leftWipe = null; - rightWipe = null; - } - } - public MutableGCodeSource getCombinedFile() - { - return result; - } - - /** - * This method handles shuffling together two gcodes, it first executes - * preprocessing and then hands the gcodes off to Layer_Helper - * - */ - public void combine() - { - MutableGCodeSource left, right; - - // load our layers into something we can use - left = new MutableGCodeSource(leftFile); - right = new MutableGCodeSource(rightFile); - - // remove some tags we don't want/get - SkeinforgePostProcessor.stripNonLayerTagComments(left); - SkeinforgePostProcessor.stripNonLayerTagComments(right); - - // load our layers into something we can *really* use - LinkedList leftLayers = parseLayers(left); - LinkedList rightLayers = parseLayers(right); - - // merge our layers into one list - final LinkedList layers = doMerge(leftLayers, rightLayers); - - // refresh and repopulate our result - result = new MutableGCodeSource(); - for(Layer l : layers) { - result.add(l.getCommands()); - } - - // add start gcode, updated based on settings - SkeinforgePostProcessor.prependAndModifyStartCode(result, startGCode); - // add end code - Layer endLayer = new Layer(Double.MAX_VALUE, endGCode.asList()); - result.add(endLayer.toString()); - // interlace progress updates - result.addProgressUpdates(); - } - -// /** -// * removes all lines that are skeinforge tag comments, but not layer tags. -// */ -// public void stripNonLayerTagComments(MutableGCodeSource source) { -// String line; -// for(Iterator i = source.iterator(); i.hasNext();) -// { -// line = i.next(); -// -// if(line.startsWith("(<") && !(line.startsWith("(") || line.startsWith("( testParseLayers(final GCodeSource source) - { - /* - * So this is a little more complicated than just breaking up stuff by Z height, - * there may be M commands between layers, some of which belong to the previous - * layer, and some to the next. - * To get around this we: - * Walk through the source - * // this assumes that every layer ends with the extruder off - * keep a trailing pointer to the last M103 we saw, and a count of the last layer height - * we saw when we see a new layer height, break off a new layer after the previous M103 - * - * but, with 5d, there won't be any M103, layers should have no associated pre/post Mcodes - * - */ - - final LinkedList layers = new LinkedList(); - final Queue read = new LinkedList(); - - //debug code/////////////////////////// - layers.add(new Layer(0d, new ArrayList(){{add("(*************start layer*************)");}})); - ////////////////////////////////////// - String lastM103 = null; - double lastZHeight = Double.MIN_VALUE; - for(String line : source) - { - GCodeCommand gcode = new GCodeCommand(line); - - if(gcode.getCodeValue('M') == 103) - lastM103 = line; - - if(gcode.hasCode('Z')) - { - double newZ = gcode.getCodeValue('Z'); - - // keeps us from creating an initial, empty layer - if(lastZHeight == Double.MIN_VALUE) - { - lastZHeight = newZ; - } - else if(newZ > lastZHeight) - { - ArrayList tmpLayer = new ArrayList(); - - // fill the tmpLayer with the accumulated lines, up to the - // most recent "stop extruding" or until the queue is empty (5D) - while(read.peek() != null && read.peek() != lastM103) - tmpLayer.add(read.poll()); - - // Also grab the M103, if present - if(read.peek() == lastM103) - tmpLayer.add(read.poll()); - - // put it in a new layer - layers.add(new Layer(lastZHeight, tmpLayer)); - - // record our next layer height - lastZHeight = newZ; - } - } - - read.add(line); - } - - //debug code/////////////////////////// - layers.add(new Layer(0d, new ArrayList(){{add("(*************end layer*************)");}})); - ////////////////////////////////////// - return layers; - } - - /** - * parseLayers is an improvement on the old parseLayers from Noah, etc. 's dualstrusion, - * but uses the same basic method because skeinforge is what it is. - * look for layer tags, break up the file using those tags. - * @param source - * @return - */ - private LinkedList parseLayers(GCodeSource source) - { - final LinkedList result = new LinkedList(); - String line; - - for(Iterator it = source.iterator(); it.hasNext();) - { - line = it.next(); - if(line.startsWith("(")) - { - // Get the layer height (or whatever SF claims it is) - float layerHeight = 0; - try - { - layerHeight = Float.parseFloat(line.split(" ")[1]); - } - catch(NumberFormatException e) - { - Base.logger.log(Level.SEVERE, "one of your layer heights was unparseable, " + - "please check and make sure all of them are in the format ( 0.00)"); - } - - //collect every command up to the end of the layer - final List accumulate = new ArrayList(); -// String next = it.next(); actually, let's keep the initial layer tag - String next = line; - while(!next.startsWith("()")) - { - accumulate.add(next); - next = it.next(); - } - //skip empty layers - if(accumulate.size() > 1) - result.add(new Layer(layerHeight, accumulate)); - } - } - - return result; - } - /** - * A toolchange is the code that goes in between commands for one head and commands for the other - * this function creates a toolchange from a tool doing one layer to a tool doing another layer - */ - private Layer toolchange(final ToolheadAlias fromTool, final Layer fromLayer, final ToolheadAlias toTool, final Layer toLayer) - { - /* - * How does a toolchange work? Glad you asked: - * First we need to do any operations relating to the previous nozzle. - * I think this is only a small reversal. It needs to be small because - * the previous layer may have ended with a reversal, and if we then - * reverse on top of that we'll lose the filament. - * We need to prepare the nozzle that we're switching to, which means - * doing a purge and wipe, if available. - * The purge is to undo the reversal from before, the wipe rubs the - * nozzle across a special piece on the machine. - * If wipes are turned off, do we still do purge? because that could - * end us up with all kindsa junk on the outside of the object. - * For wipes: Since we're moving to another position to do the wipe, we - * have to record the next position we want to be at, because if we - * start the next layer from a random place we might end up spewing - * plastic all the way to that point. - * At the end of a toolchange, we should disable whichever extruder is - * not being used using M18 A B (on the next call to whichever axis - * it'll start up again) - * - * toolchange psudocode: - * - * Layer toolchange = new Layer - * - * if wipes - * layer.add(wipes) - * - * nextPos = get next position (first G1 of next layer) - * layer.add(move up, perhaps just above the next layer height, as quickly as is reasonable) - * layer.add(move to nextPos, also fairly quickly) - * layer.add(set speed to F from nextPos, or, - * if that's not present, the last F from the previous layer) - * - * layer.add(M18 A B) - */ - final ArrayList result = new ArrayList(); - //debug code/////////////////////////// - result.add("(*************start toolchange*************)"); - ////////////////////////////////////// - if(useWipes) - { - // The left/right distinction isn't actually important here - // on a tom you have to wipe both heads, and on a replicator - // wiping either does both - result.addAll(wipe(leftWipe)); - if(machineType != MachineType.THE_REPLICATOR) - result.addAll(wipe(rightWipe)); - } - - result.add(toTool.getRecallOffsetGcodeCommand()); - result.add("M108 "+toTool.getTcode() + "(Set tool)"); - - // Ben's suggestion - result.add("M18 A B"); - - final DecimalFormat nf = (DecimalFormat)Base.getGcodeFormat(); - final Point5d firstPos = getFirstPosition(toLayer); - firstPos.setZ(getLayerZ(toLayer)); - - if(firstPos != null) - { - // The F here is a magic number, you can read about it in the 'wipe()' function - // move up fairly quickly - result.add("G1 Z" + nf.format(firstPos.z()) +" F3000"); - // move to the next point - result.add("G1 X" + nf.format(firstPos.x()) + " Y" + nf.format(firstPos.y()) + " Z" + nf.format(firstPos.z()) +" F3000"); - } -// else -// { -//// System.err.print(toLayer); -// } - - //TODO: catch possible null pointer exceptions? - // set the feedrate with an empty G1 - String feedrate = getFirstFeedrate(toLayer); - if(feedrate.equals("")) - feedrate = getLastFeedrate(fromLayer); - result.add("G1 " + feedrate); - - - //debug code/////////////////////////// - result.add("(*************end toolchange*************)"); - ////////////////////////////////////// - // The 'height' of the toolchange. just the average of the surrounding layers because why not? - final double height = (toLayer.getHeight() - fromLayer.getHeight())/2; - - return new Layer(height, result); - } - /** - * gets the first G1 from a layer, returns the position of X, Y, Z axes - * @param l - * @return - */ - private Point5d getFirstPosition(final Layer l) - { - final List search = l.getCommands(); - GCodeCommand gcode; - for(int i = 0; i < search.size(); i++) - { - gcode = new GCodeCommand(search.get(i)); - if(gcode.getCodeValue('G') == 1) - { - Point5d result = new Point5d(); - result.setX(gcode.getCodeValue('X')); - result.setY(gcode.getCodeValue('Y')); - result.setZ(gcode.getCodeValue('Z')); - return result; - } - } - return null; - } - - /** - * Apparently skeinforge does not have all the moves in a layer at the same height. - * The first one is frequently lower than the following ones, so this function finds - * the last height listed in a layer - * @param l the layer in which to look - * @return the layer height (maybe) - */ - private Double getLayerZ(final Layer l) - { - final List search = l.getCommands(); - GCodeCommand gcode; - for(int i = search.size()-1; i >= 0; i--) - { - gcode = new GCodeCommand(search.get(i)); - if(gcode.getCodeValue('G') == 1 && gcode.hasCode('Z')) - { - return gcode.getCodeValue('Z'); - } - } - return null; - } - - /** - * This gets the last feedrate used in a layer - * @param l - * @return - */ - private String getLastFeedrate(final Layer l) - { - final List search = l.getCommands(); - GCodeCommand gcode; - for(int i = search.size()-1; i >= 0; i--) - { - gcode = new GCodeCommand(search.get(i)); - if(gcode.getCodeValue('F') != -1) - return "F"+Base.getGcodeFormat().format(gcode.getCodeValue('F')); - } - return ""; - } - /** - * This gets the first feedrate used in a layer - * @param l - * @return - */ - private String getFirstFeedrate(final Layer l) - { - final List search = l.getCommands(); - GCodeCommand gcode; - for(int i = 0; i < search.size(); i++) - { - gcode = new GCodeCommand(search.get(i)); - if(gcode.getCodeValue('F') != -1) - return "F"+Base.getGcodeFormat().format(gcode.getCodeValue('F')); - } - return ""; - } - - /** - * **CURRENTLY UNTESTED** - * A wipe is something that can be attached to a machine to rub the toolhead over and - * clear it of excess plastic. the WipeModel specifies a before position and an after position - * as well as some parameters for extruding some plastic before wiping to prime the nozzle. - * - * this function will always return the same thing for a given wipe, we could easily cache - * that thing and make this much more efficient. - * @param toolWipe - * @return - */ - private ArrayList wipe(final WipeModel toolWipe) - { - final ArrayList result = new ArrayList(); - - //debug code/////////////////////////// - result.add("(*************start wipe*************)"); - ////////////////////////////////////// +package replicatorg.app.gcode; - // This is a not-entirely-arbitrarily chosen number - // Ben or Noah may be able to explain it, - // Ted might be able to by the time you ask - final String feedrate = "F3000"; - // move to purge home - result.add("G53"); - - // Ben and Ted had a chat and believe that it is almost always safe to do the move for wipes in this order - result.add("G1 " + toolWipe.getY1() +" "+ feedrate); - result.add("G1 " + toolWipe.getZ1() +" "+ feedrate); +import java.io.File; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.logging.Level; + +import javax.swing.JOptionPane; + +import replicatorg.app.Base; +import replicatorg.machine.model.MachineType; +import replicatorg.machine.model.ToolheadAlias; +import replicatorg.machine.model.WipeModel; +import replicatorg.model.GCodeSource; +import replicatorg.plugin.toolpath.skeinforge.SkeinforgePostProcessor; +import replicatorg.util.Point5d; + + +/** + * This class takes two existing gcode files and merges them into a single gcode that can be run on a dualstrusion printer + * + * TODO: + * some small changes to try, see what they do to the print: + * tiny hops (~1mm) + * in toolchange - get max(nextFeed, lastFeed) + * + * @author Noah Levy + * @maintained Ted + * Modified by Richard Parkins + */ +public class DualStrusionConstruction +{ + private final File leftFile, rightFile; + private final boolean useWipes; + private final WipeModel leftWipe; + private final WipeModel rightWipe; + private final MachineType machineType; + private final boolean pauseOnChange; + private MutableGCodeSource result; + /* If we see no comments before the first , we assume that we're + * generating for a printer that doesn't handle comments and the user + * has removed all except the and that we need, so we + * don't copy those to the output or put in any of our own. + */ + private boolean seenComment; + private Point5d homePos; + + public DualStrusionConstruction(File leftFile, File rightFile, + MachineType type, boolean useWipes) + { + this.leftFile = leftFile; + this.rightFile = rightFile; + this.useWipes = useWipes; + this.machineType = type; + this.seenComment = false; + this.homePos = null; + this.pauseOnChange = + Base.preferences.getBoolean("dualstrusionwindow.pauseonchange", + false); + if(useWipes) + { + leftWipe = Base.getMachineLoader().getMachineInterface().getModel().getWipeFor(ToolheadAlias.LEFT); + rightWipe = Base.getMachineLoader().getMachineInterface().getModel().getWipeFor(ToolheadAlias.RIGHT); + + if(leftWipe == null || rightWipe == null) + { + String error = "Could not find wipes for the current machine: " + + Base.getMachineLoader().getMachineInterface().getModel().toString() + ". Continuing without wipes."; + JOptionPane.showConfirmDialog(null, error, + "Could not find wipes!", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE); + + useWipes = false; + } + } + else + { + leftWipe = null; + rightWipe = null; + } + } + public MutableGCodeSource getCombinedFile() + { + return result; + } + + /** + * This method handles shuffling together two gcodes, it first executes + * preprocessing and then hands the gcodes off to doMerge() + * + */ + public void combine() + { + MutableGCodeSource left, right; + + // load our layers into something we can use + left = new MutableGCodeSource(leftFile); + right = new MutableGCodeSource(rightFile); + + // load our layers into something we can *really* use + LinkedList leftLayers = parseLayers(left, 1); + LinkedList rightLayers = parseLayers(right, 0); + + // merge our layers into one list + final LinkedList layers = doMerge(leftLayers, rightLayers); + + // refresh and repopulate our result + result = new MutableGCodeSource(); + for(Layer l : layers) { + result.add(l.getCommands()); + } + // interlace progress updates + result.addProgressUpdates(); + } + + /** + * parseLayers is an improvement on the old parseLayers from Noah, etc. 's dualstrusion, + * but uses the same basic method because skeinforge is what it is. + * look for layer tags, break up the file using those tags. + * @param source + * @return + */ + private LinkedList parseLayers(GCodeSource source, int toolNum) + { + final LinkedList result = new LinkedList(); + String line; + + String prefix; + String oldTool; + String newTool; + String oldOffset; + String newOffset; + if (toolNum == 0) { + prefix = new String("( "); + oldTool = ToolheadAlias.LEFT.getTcode(); + newTool = ToolheadAlias.RIGHT.getTcode(); + oldOffset = ToolheadAlias.LEFT.getRecallOffsetGcodeCommand(); + newOffset = ToolheadAlias.RIGHT.getRecallOffsetGcodeCommand(); + } + else { // assume must be 1 + prefix = new String("( "); + oldTool = ToolheadAlias.RIGHT.getTcode(); + newTool = ToolheadAlias.LEFT.getTcode(); + oldOffset = ToolheadAlias.RIGHT.getRecallOffsetGcodeCommand(); + newOffset = ToolheadAlias.LEFT.getRecallOffsetGcodeCommand(); + } + + // start the first layer + List accumulate = new ArrayList(); + + float layerHeight = 0; + for(Iterator it = source.iterator(); it.hasNext();) + { + // get a source line + line = it.next(); + if (line.startsWith("(")) { + // it's a comment + if (line.startsWith("(")) { + // end layer + if (layerHeight < 0) { + Base.logger.log(Level.SEVERE, "End layer with no start\n"); + layerHeight = 0; + } + // accumulate layer if not empty + if (accumulate.size() > 0) { + if (this.seenComment) { + accumulate.add(prefix + line.substring(1)); + } + result.add(new Layer(layerHeight, accumulate)); + accumulate = new ArrayList(); + } + layerHeight = -1; + } + else if (line.startsWith("(")) { + // Get the layer height (or whatever SF claims it is) + layerHeight = 0; + try + { + layerHeight = Float.parseFloat(line.split(" ")[1]); + } + catch(NumberFormatException e) + { + Base.logger.log(Level.SEVERE, "one of your layer heights was unparseable, " + + "please check and make sure all of them are in the format ( 0.00)"); + } + if (this.seenComment) { + accumulate.add(prefix + line.substring(1)); + } + } + else { + // other comment, just accumulate with prefix + accumulate.add(prefix + line.substring(1)); + this.seenComment = true; + } + } + else { + // not a comment, accumulate without prefix + if (!line.startsWith("G10")) { + line = line.replace(oldTool, newTool); + line = line.replace(oldOffset, newOffset); + } + accumulate.add(line); + } + } + if (accumulate.size() > 0) { + // save any end matter after last real layer with a silly height + result.add(new Layer(999999, accumulate)); + } + return result; + } + + /** + * A toolchange is the code that goes in between commands for one head and commands for the other + * this function creates a toolchange from a tool doing one layer to a tool doing another layer + */ + private Layer toolchange(final ToolheadAlias fromTool, final Layer fromLayer, final ToolheadAlias toTool, final Layer toLayer) + { + /* + * How does a toolchange work? Glad you asked: + * First we need to do any operations relating to the previous nozzle. + * I think this is only a small reversal. It needs to be small because + * the previous layer may have ended with a reversal, and if we then + * reverse on top of that we'll lose the filament. + * We need to prepare the nozzle that we're switching to, which means + * doing a purge and wipe, if available. + * The purge is to undo the reversal from before, the wipe rubs the + * nozzle across a special piece on the machine. + * If wipes are turned off, do we still do purge? because that could + * end us up with all kindsa junk on the outside of the object. + * For wipes: Since we're moving to another position to do the wipe, we + * have to record the next position we want to be at, because if we + * start the next layer from a random place we might end up spewing + * plastic all the way to that point. + * At the end of a toolchange, we should disable whichever extruder is + * not being used using M18 A B (on the next call to whichever axis + * it'll start up again) + * + * toolchange psudocode: + * + * Layer toolchange = new Layer + * + * if wipes + * layer.add(wipes) + * + * nextPos = get next position (first G1 of next layer) + * layer.add(move up, perhaps just above the next layer height, as quickly as is reasonable) + * layer.add(move to nextPos, also fairly quickly) + * layer.add(set speed to F from nextPos, or, + * if that's not present, the last F from the previous layer) + * + * layer.add(M18 A B) + */ + final ArrayList result = new ArrayList(); + //debug code/////////////////////////// + result.add("(*************start toolchange*************)"); + ////////////////////////////////////// + if(useWipes) + { + // The left/right distinction isn't actually important here + // on a tom you have to wipe both heads, and on a replicator + // wiping either does both + result.addAll(wipe(leftWipe)); + if(machineType != MachineType.THE_REPLICATOR) + result.addAll(wipe(rightWipe)); + } + + final DecimalFormat nf = (DecimalFormat)Base.getGcodeFormat(); + final Point5d firstPos = getFirstPosition(toLayer); + if(firstPos != null) + { + firstPos.setZ(getLayerZ(toLayer)); + } + + if (pauseOnChange) + { + if (firstPos != null) + { + if (homePos == null) + { + homePos = new Point5d(); + homePos.setY(-70.0); + } + // move up fairly quickly + result.add("G1 Y" + nf.format(homePos.y()) + + " Z" + nf.format(firstPos.z() + 10.0) + + " F3000"); + } + result.add("M72 P2"); + result.add( + "M71 (Wait for oozing to finish and then press OK)"); + result.add("M70 P1 (Continuing...)"); + } + // Offets deprecated nowadays, but this seems to be needed + result.add(toTool.getRecallOffsetGcodeCommand()); + result.add("M108 "+toTool.getTcode() + " (Set tool)"); + + // Ben's suggestion + result.add("M18 A B"); + + //TODO: catch possible null pointer exceptions? + // set the feedrate with an empty G1 + String feedrate = getFirstFeedrate(toLayer); + if(feedrate.equals("")) + feedrate = getLastFeedrate(fromLayer); + + if(firstPos != null) + { + // The F here is a magic number, you can read about it in the 'wipe()' function + if (!pauseOnChange) + { + // move up fairly quickly + result.add("G1 Z" + nf.format(firstPos.z()) +" F3000"); + } + // move to the next point + result.add("G1 X" + nf.format(firstPos.x()) + + " Y" + nf.format(firstPos.y()) + + " Z" + nf.format(firstPos.z()) + + " " + feedrate); + } +// else +// { +//// System.err.print(toLayer); +// } + + result.add("G1 " + feedrate); + + + //debug code/////////////////////////// + result.add("(*************end toolchange*************)"); + ////////////////////////////////////// + // The 'height' of the toolchange. just the average of the surrounding layers because why not? + final double height = (toLayer.getHeight() - fromLayer.getHeight())/2; + + return new Layer(height, result); + } + /** + * gets the first G1 from a layer, returns the position of X, Y, Z axes + * @param l + * @return + */ + private Point5d getFirstPosition(final Layer l) + { + final List search = l.getCommands(); + GCodeCommand gcode; + for(int i = 0; i < search.size(); i++) + { + gcode = new GCodeCommand(search.get(i)); + if(gcode.getCodeValue('G') == 1) + { + Point5d result = new Point5d(); + result.setX(gcode.getCodeValue('X')); + result.setY(gcode.getCodeValue('Y')); + result.setZ(gcode.getCodeValue('Z')); + return result; + } + } + return null; + } + + /** + * Apparently skeinforge does not have all the moves in a layer at the same height. + * The first one is frequently lower than the following ones, so this function finds + * the last height listed in a layer + * @param l the layer in which to look + * @return the layer height (maybe) + */ + private Double getLayerZ(final Layer l) + { + final List search = l.getCommands(); + GCodeCommand gcode; + for(int i = search.size()-1; i >= 0; i--) + { + gcode = new GCodeCommand(search.get(i)); + if(gcode.getCodeValue('G') == 1 && gcode.hasCode('Z')) + { + return gcode.getCodeValue('Z'); + } + } + return null; + } + + /** + * This gets the last feedrate used in a layer + * @param l + * @return + */ + private String getLastFeedrate(final Layer l) + { + final List search = l.getCommands(); + GCodeCommand gcode; + for(int i = search.size()-1; i >= 0; i--) + { + gcode = new GCodeCommand(search.get(i)); + if(gcode.getCodeValue('F') != -1) + return "F"+Base.getGcodeFormat().format(gcode.getCodeValue('F')); + } + return ""; + } + /** + * This gets the first feedrate used in a layer + * @param l + * @return + */ + private String getFirstFeedrate(final Layer l) + { + final List search = l.getCommands(); + GCodeCommand gcode; + for(int i = 0; i < search.size(); i++) + { + gcode = new GCodeCommand(search.get(i)); + if(gcode.getCodeValue('F') != -1) + return "F"+Base.getGcodeFormat().format(gcode.getCodeValue('F')); + } + return ""; + } + + /** + * **CURRENTLY UNTESTED** + * A wipe is something that can be attached to a machine to rub the toolhead over and + * clear it of excess plastic. the WipeModel specifies a before position and an after position + * as well as some parameters for extruding some plastic before wiping to prime the nozzle. + * + * this function will always return the same thing for a given wipe, we could easily cache + * that thing and make this much more efficient. + * @param toolWipe + * @return + */ + private ArrayList wipe(final WipeModel toolWipe) + { + final ArrayList result = new ArrayList(); + + //debug code/////////////////////////// + result.add("(*************start wipe*************)"); + ////////////////////////////////////// + + // This is a not-entirely-arbitrarily chosen number + // Ben or Noah may be able to explain it, + // Ted might be able to by the time you ask + final String feedrate = "F3000"; + + // move to purge home + result.add("G53"); + + // Ben and Ted had a chat and believe that it is almost always safe to do the move for wipes in this order + result.add("G1 " + toolWipe.getY1() +" "+ feedrate); + result.add("G1 " + toolWipe.getZ1() +" "+ feedrate); result.add("G1 " + toolWipe.getX1() +" "+ feedrate); - - // purge current toolhead - result.add("M108 "+toolWipe.getPurgeRPM()); - result.add("M101"); - result.add("G04 "+toolWipe.getPurgeDuration()); - result.add("M103"); - - // reverse current toolhead - result.add("M108 "+toolWipe.getReverseRPM()); - result.add("M102"); - result.add("G04 "+toolWipe.getReverseDuration()); - result.add("M103"); - // wait for leak - result.add("G04 " + toolWipe.getWait()); - - // move to second wipe position - result.add("G1 " + toolWipe.getX2() +" "+ toolWipe.getY2() +" "+ toolWipe.getZ2() +" "+ feedrate); - - //debug code/////////////////////////// - result.add("(*************end wipe*************)"); - ////////////////////////////////////// - return result; - } - - /** - * This will consume two LinkedLists of Layers and return a combined List of Layers - * representing a dualstrusion print, with all the appropriate toolchanges inserted. - * @param left - * @param right - */ - private LinkedList doMerge(final LinkedList left, final LinkedList right) - { - /* - * Merging layers should look something like this: - * Queue A, B; - * List result - * A = layers from one file, sorted from least to greatest - * B = layers from other file, sorted from least to greatest - * last = null - * while A && B are not empty - * if A.peek.height < B.peek.height - * if last == B - * result.append(toolchange B to A) - * result.append(A.pop) - * last = A - * else if B.peek.height < A.peek.height - * if last == A - * result.append(toolchange A to B) - * result.append(B.pop) - * last = B - * else // they're of equal height - * if last != null - * if last == A - * result.append(A.pop) - * else if last == B - * result.append(B.pop) - * else - * result.append(A.pop) - * // at this point one of them is empty - * if A is not empty - * if last == B - * result.append(toolchange B to A) - * result.appendAll(A) - * if B is not empty - * if last == A - * result.append(toolchange A to B) - * result.appendAll(B) - * - * - */ - // using a LinkedList means we can getLast() - final LinkedList result = new LinkedList(); - - // this is just a handy way to keep track of where our last layer came from - Object lastLayer = null; - - - final ToolheadAlias initialTool; - // Start by selecting the correct toolhead - // This mimics how the selection happens in the loop below - if(right.peek().getHeight() < left.peek().getHeight()) - initialTool = ToolheadAlias.RIGHT; - else - initialTool = ToolheadAlias.LEFT; - - // Prepend the switch to correct tool to the whole thing - result.add(new Layer(0, new ArrayList(){{ - add(initialTool.getRecallOffsetGcodeCommand()); - add("M108 "+initialTool.getTcode() + "(Set tool)"); - }})); - - // loop while we still have layers to merge - while((!left.isEmpty()) || (!right.isEmpty())) - { - // if we've used all of our right layers, keep grabbing from left - if(right.isEmpty()) - { - // if last layer tool != next layer tool, add a toolchange - if(right.equals(lastLayer)) - result.add(toolchange(ToolheadAlias.RIGHT, result.getLast(), ToolheadAlias.LEFT, left.peek())); - result.add(left.pop()); - lastLayer = left; - } - else if(left.isEmpty()) // used all left layers, keep grabbing from right - { - // if last layer tool != next layer tool, add a toolchange - if(left.equals(lastLayer)) - result.add(toolchange(ToolheadAlias.LEFT, result.getLast(), ToolheadAlias.RIGHT, right.peek())); - result.add(right.pop()); - lastLayer = right; - } - else if(left.peek().getHeight() < right.peek().getHeight()) // left has a lower layer, grab it - { - // if last layer tool != next layer tool, add a toolchange - if(right.equals(lastLayer)) - result.add(toolchange(ToolheadAlias.RIGHT, result.getLast(), ToolheadAlias.LEFT, left.peek())); - result.add(left.pop()); - lastLayer = left; - } - else if(right.peek().getHeight() < left.peek().getHeight()) // right has lower layer - { - // if last layer tool != next layer tool, add a toolchange - if(left.equals(lastLayer)) - result.add(toolchange(ToolheadAlias.LEFT, result.getLast(), ToolheadAlias.RIGHT, right.peek())); - result.add(right.pop()); - lastLayer = right; - } - else //equal height - { - if(lastLayer == null) - { - //arbitrary - result.add(left.pop()); - lastLayer = left; - } - else - { - if(lastLayer == left) - result.add(left.pop()); - else// if(lastLayer == right) - result.add(right.pop()); - } - } - } - - return result; - } - -// // This is a hack, really we should be getting the dual-head start code -// private void duplicateToolheadLines(final MutableGCodeSource source) -// { -// int idx = 0; -// String line; -// double toolhead; -// final List sourceList = source.asList(); -// for(int i = 0; i < source.getLineCount(); i++) -// { -// line = sourceList.get(i); -// idx++; -// GCodeCommand gcode = new GCodeCommand(line); -// -// toolhead = gcode.getCodeValue('T'); -// if(toolhead == 0) -// source.add(idx, line.replace("T0", "T1")); -// if(toolhead == 1) -// source.add(line.replace("T1", "T0")); -// if(toolhead != -1) -// i++; -// -// } -// } -} + + // purge current toolhead + result.add("M108 "+toolWipe.getPurgeRPM()); + result.add("M101"); + result.add("G04 "+toolWipe.getPurgeDuration()); + result.add("M103"); + + // reverse current toolhead + result.add("M108 "+toolWipe.getReverseRPM()); + result.add("M102"); + result.add("G04 "+toolWipe.getReverseDuration()); + result.add("M103"); + + // wait for leak + result.add("G04 " + toolWipe.getWait()); + + // move to second wipe position + result.add("G1 " + toolWipe.getX2() +" "+ toolWipe.getY2() +" "+ toolWipe.getZ2() +" "+ feedrate); + + //debug code/////////////////////////// + result.add("(*************end wipe*************)"); + ////////////////////////////////////// + return result; + } + + /** + * This will consume two LinkedLists of Layers and return a combined List of Layers + * representing a dualstrusion print, with all the appropriate toolchanges inserted. + * First layer and any end matter after last are treated specially + * @param left + * @param right + */ + private LinkedList doMerge(final LinkedList left, final LinkedList right) + { + /* + * Merging layers should look something like this: + * Queue A, B; + * List result + * A = layers from one file, sorted from least to greatest + * B = layers from other file, sorted from least to greatest + * last = null + * while A && B are not empty + * if A.peek.height < B.peek.height + * if last == B + * result.append(toolchange B to A) + * result.append(A.pop) + * last = A + * else if B.peek.height < A.peek.height + * if last == A + * result.append(toolchange A to B) + * result.append(B.pop) + * last = B + * else // they're of equal height + * if last != null + * if last == A + * result.append(A.pop) + * else if last == B + * result.append(B.pop) + * else + * result.append(A.pop) + * // at this point one of them is empty + * if A is not empty + * if last == B + * result.append(toolchange B to A) + * result.appendAll(A) + * if B is not empty + * if last == A + * result.append(toolchange A to B) + * result.appendAll(B) + * + * + */ + // using a LinkedList means we can getLast() + final LinkedList result = new LinkedList(); + + // this is just a handy way to keep track of where our last layer came from + Object lastLayer = null; + + // special merge code for initial layers + // This is a bit dependent on users not modifying start.gcode too much + if ((!left.isEmpty()) && (!right.isEmpty())) { + ArrayList start = new ArrayList(); + ArrayList dominant; + ArrayList secondary; + if (this.seenComment) { + start.add("(**** Merged startup gcode for Dualstrusion ****)"); + } + if ( (left.peek().getHeight() != 0) + || (right.peek().getHeight() != 0)) { + Base.logger.log(Level.SEVERE, + "One of your gcode files did not have the required" + + " at the end of its start.gcode.\n" + + "Please use a standard start.gcode.\n"); + } + ToolheadAlias initialTool; + ToolheadAlias otherTool; + if(right.get(1).getHeight() < left.get(1).getHeight()) { + initialTool = ToolheadAlias.RIGHT; + otherTool = ToolheadAlias.LEFT; + dominant = (ArrayList)right.pop().getCommands(); + secondary = (ArrayList)left.pop().getCommands(); + } + else { + initialTool = ToolheadAlias.LEFT; + otherTool = ToolheadAlias.RIGHT; + dominant = (ArrayList)left.pop().getCommands(); + secondary = (ArrayList)right.pop().getCommands(); + } + while (!dominant.isEmpty()) { + String s = dominant.get(0); + if (s.startsWith("M6")) { + break; + } + else { + start.add(s); + dominant.remove(0); + } + } + while (!secondary.isEmpty()) { + String s = secondary.get(0); + if (s.startsWith("(")) { + start.add(s); + } + else if (s.startsWith("M104")) { + start.add(s); + } + else if (s.startsWith("M6")) { + break; + } + secondary.remove(0); + } + if (!dominant.isEmpty()) { + start.add(dominant.get(0)); + dominant.remove(0); + } + if (!secondary.isEmpty()) { + start.add(secondary.get(0)); + secondary.remove(0); + } + start.add("M108 " + initialTool.getTcode() + " (Set tool)"); + while (!dominant.isEmpty()) { + String s = dominant.get(0); + if ((homePos == null) && s.startsWith("G0")) { + GCodeCommand gcode = new GCodeCommand(s); + homePos = new Point5d(); + homePos.setY(gcode.getCodeValue('Y')); + } + start.add(s); + dominant.remove(0); + } + start.add("M108 " + otherTool.getTcode() + " (Set tool)"); + while (!secondary.isEmpty()) { + start.add(secondary.get(0)); + secondary.remove(0); + } + start.add("M108 " + initialTool.getTcode() + " (Set tool)"); + result.add(new Layer(0.0, start)); + } + + // loop while we still have layers to merge + boolean doneEnd = false; + while((!left.isEmpty()) || (!right.isEmpty())) + { + // if we've used all of our right layers, keep grabbing from left + if(right.isEmpty()) + { + if (left.peek().getHeight() < 999999) { + // if last layer tool != next layer tool, add a toolchange + if(right.equals(lastLayer)) { + result.add(toolchange(ToolheadAlias.RIGHT, result.getLast(), ToolheadAlias.LEFT, left.peek())); + } + result.add(left.pop()); + lastLayer = left; + } + else { + ArrayList finish = new ArrayList(); + ArrayList commands; + commands = (ArrayList)left.pop().getCommands(); + while (!commands.isEmpty()) { + String s = commands.get(0); + if ( s.startsWith("(") + || ( (!s.startsWith("M104")) + && !doneEnd)) { + finish.add(s); + } + commands.remove(0); + } + result.add(new Layer(999999, finish)); + doneEnd = true; + } + } + else if(left.isEmpty()) // used all left layers, keep grabbing from right + { + if (right.peek().getHeight() < 999999) { + // if last layer tool != next layer tool, add a toolchange + if(left.equals(lastLayer)) { + result.add(toolchange(ToolheadAlias.LEFT, result.getLast(), ToolheadAlias.RIGHT, right.peek())); + } + result.add(right.pop()); + lastLayer = right; + } + else { + ArrayList finish = new ArrayList(); + ArrayList commands; + commands = (ArrayList)right.pop().getCommands(); + while (!commands.isEmpty()) { + String s = commands.get(0); + if ( s.startsWith("(") + || ( (!s.startsWith("M104")) + && !doneEnd)) { + finish.add(s); + } + commands.remove(0); + } + result.add(new Layer(999999, finish)); + doneEnd = true; + } + } + else if (left.peek().getHeight() < right.peek().getHeight()) + { + // left has a lower layer, grab it + // if last layer tool != next layer tool, add a toolchange + if (!left.equals(lastLayer)) { + result.add(toolchange(ToolheadAlias.RIGHT, result.getLast(), ToolheadAlias.LEFT, left.peek())); + } + result.add(left.pop()); + lastLayer = left; + if (left.peek().getHeight() == 999999) { + ArrayList finish = new ArrayList(); + finish.add("M104 S0 " + ToolheadAlias.LEFT.getTcode() + + " (done with left extruder, cool it"); + result.add(new Layer(999999, finish)); + } + } + else if (right.peek().getHeight() < left.peek().getHeight()) + { + // right has lower layer + // if last layer tool != next layer tool, add a toolchange + if (!right.equals(lastLayer)) { + result.add(toolchange(ToolheadAlias.LEFT, result.getLast(), ToolheadAlias.RIGHT, right.peek())); + + } + result.add(right.pop()); + lastLayer = right; + if (right.peek().getHeight() == 999999) { + ArrayList finish = new ArrayList(); + finish.add("M104 S0 " + ToolheadAlias.RIGHT.getTcode() + + " (done with right extruder, cool it"); + result.add(new Layer(999999, finish)); + } + } + else //equal height + { + if (lastLayer == null) + { + result.add(toolchange(ToolheadAlias.RIGHT, result.getLast(), ToolheadAlias.LEFT, left.peek())); + lastLayer = left; + } + if (lastLayer == left) + { + if (left.peek().getHeight() == 999999) { + ArrayList finish = new ArrayList(); + ArrayList commands; + commands = (ArrayList)left.pop().getCommands(); + while (!commands.isEmpty()) { + String s = commands.get(0); + if ( s.startsWith("(") + || ( (!s.startsWith("M104")) + && !doneEnd)) { + finish.add(s); + } + commands.remove(0); + } + result.add(new Layer(999999, finish)); + doneEnd = true; + } + else + { + result.add(left.pop()); + lastLayer = left; + if (left.peek().getHeight() == 999999) { + ArrayList finish = new ArrayList(); + finish.add("M104 S0 " + ToolheadAlias.LEFT.getTcode() + + " (done with left extruder, cool it"); + result.add(new Layer(999999, finish)); + } + } + } + else + { + if (right.peek().getHeight() == 999999) { + ArrayList finish = new ArrayList(); + ArrayList commands; + commands = (ArrayList)right.pop().getCommands(); + while (!commands.isEmpty()) { + String s = commands.get(0); + if ( s.startsWith("(") + || ( (!s.startsWith("M104")) + && !doneEnd)) { + finish.add(s); + } + commands.remove(0); + } + result.add(new Layer(999999, finish)); + doneEnd = true; + } + else { + result.add(right.pop()); + if (right.peek().getHeight() == 999999) { + ArrayList finish = new ArrayList(); + finish.add("M104 S0 " + ToolheadAlias.RIGHT.getTcode() + + " (done with right extruder, cool it"); + result.add(new Layer(999999, finish)); + } + } + } + } + } + return result; + } +} diff --git a/src/replicatorg/app/ui/AdvancedPrefs.java b/src/replicatorg/app/ui/AdvancedPrefs.java index ae638000b..fb59e6eae 100644 --- a/src/replicatorg/app/ui/AdvancedPrefs.java +++ b/src/replicatorg/app/ui/AdvancedPrefs.java @@ -3,19 +3,28 @@ import java.awt.Container; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.awt.font.FontRenderContext; +import java.awt.geom.Rectangle2D; import java.awt.Dimension; +import java.awt.Font; import java.io.BufferedOutputStream; import java.util.logging.Level; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; +import javax.swing.table.DefaultTableModel; import javax.swing.JFrame; +import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.KeyStroke; import replicatorg.app.Base; public class AdvancedPrefs extends JFrame { + private int leftWidth; + private int rightWidth; + private int rowCount; + private JTable prefsDisplay = new JTable(); public AdvancedPrefs() { @@ -23,9 +32,10 @@ public AdvancedPrefs() Object[][] prefs = getPreferences(); - JTable prefsDisplay = new JTable(prefs, new Object[]{"Preference name", "value"}); + prefsDisplay.setModel( + new DefaultTableModel( + prefs, new Object[]{"Preference name", "value"})); prefsDisplay.setEnabled(false); - content.add(prefsDisplay); content.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { @@ -36,20 +46,40 @@ public void keyPressed(KeyEvent e) { } } }); - this.setMinimumSize(new Dimension(300,300)); + prefsDisplay.getColumnModel().getColumn(0).setMinWidth(leftWidth); + prefsDisplay.getColumnModel().getColumn(1).setMinWidth(rightWidth); + int height = rowCount * prefsDisplay.getRowHeight(); + Dimension size = new Dimension(leftWidth * 2, height); + prefsDisplay.setPreferredScrollableViewportSize(size); + prefsDisplay.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + content.add(new JScrollPane(prefsDisplay)); pack(); } private Object[][] getPreferences() { + Object[][] result; Preferences p = Base.preferences; try { + Font font = prefsDisplay.getFont(); + FontRenderContext frc = + prefsDisplay.getFontMetrics(font).getFontRenderContext(); String[] pNames = p.keys(); - result = new Object[pNames.length][2]; - for(int i = 0; i < pNames.length; i++) + rowCount = pNames.length; + result = new Object[rowCount][2]; + leftWidth = 0; + rightWidth = 0; + for(int i = 0; i < rowCount; i++) { - result[i] = new String[]{pNames[i], p.get(pNames[i], "")}; + String s[] = new String[]{pNames[i], p.get(pNames[i], "")}; + Rectangle2D r = font.getStringBounds(s[0], frc); + int x = (int)(r.getWidth() * 1.05); + if (x > leftWidth) { leftWidth = x; } + r = font.getStringBounds(s[1], frc); + x = (int)(r.getWidth() * 1.05); + if (x > rightWidth) { rightWidth = x; } + result[i] = s; } } catch (BackingStoreException e) { diff --git a/src/replicatorg/app/ui/DualStrusionWindow.java b/src/replicatorg/app/ui/DualStrusionWindow.java index cd939d993..29ba0adbf 100644 --- a/src/replicatorg/app/ui/DualStrusionWindow.java +++ b/src/replicatorg/app/ui/DualStrusionWindow.java @@ -45,6 +45,7 @@ import java.util.logging.Level; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; @@ -96,8 +97,6 @@ public class DualStrusionWindow extends JFrame{ File rightStl = null; File leftGcode = null; File rightGcode = null; - MutableGCodeSource startSource; - MutableGCodeSource endSource; boolean failure = false; JLabel failureLabel = new JLabel(); @@ -114,9 +113,9 @@ public class DualStrusionWindow extends JFrame{ * * This is the default constructor, it is only invoked if the ReplicatorG window did not already have a piece of gcode open */ - public DualStrusionWindow(MachineType type, MutableGCodeSource startCode, MutableGCodeSource endCode) + public DualStrusionWindow(MachineType type) { - this(type, startCode, endCode, null); + this(type, null); } /** @@ -127,13 +126,11 @@ public DualStrusionWindow(MachineType type, MutableGCodeSource startCode, Mutabl * This is a constructor that takes the filepath of the gcode open currently in ReplicatorG * @param s the path of the gcode currently open in RepG */ - public DualStrusionWindow(MachineType type, MutableGCodeSource startCode, MutableGCodeSource endCode, String path) { + public DualStrusionWindow(MachineType type, String path) { super("DualStrusion Window"); Base.logger.log(Level.FINE, "Dualstrusion window booting up..."); - startSource = startCode; - endSource = endCode; this.type = type; panels = new JPanel(new CardLayout()); @@ -203,20 +200,20 @@ public void actionPerformed(ActionEvent arg0) { rightToolhead.setText(s); } }); -// JButton switchItem = new JButton("Switch Toolheads"); //This button switches the contents of the two text fields in order to easily swap Primary and Secondary Toolheads -// switchItem.addActionListener(new ActionListener() -// { -// public void actionPerformed(ActionEvent arg0) { -// String temp = leftToolhead.getText(); -// leftToolhead.setText(rightToolhead.getText()); -// rightToolhead.setText(temp); -// -// } -// }); -// panel.add(switchItem, "wrap"); - panel.add(new JLabel("Right Extruder"), "split"); - panel.add(rightToolhead,"split, growx"); - panel.add(rightChooserButton, "wrap"); + panel.add(new JLabel("Right Extruder"), "split"); + panel.add(rightToolhead,"split, growx"); + panel.add(rightChooserButton, "wrap"); + + final String pref = new String("dualstrusionwindow.pauseonchange"); + JCheckBox cb = new JCheckBox("Pause when changing tool"); + cb.setSelected(Base.preferences.getBoolean(pref, false)); + cb.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JCheckBox box = (JCheckBox)e.getSource(); + Base.preferences.putBoolean(pref, box.isSelected()); + } + }); + panel.add(cb, "wrap"); final JTextField destinationTextField = new JTextField(50); destinationTextField.setText(Base.preferences.get("dualstrusionwindow.destfile", "")); @@ -356,11 +353,15 @@ else if("gcode".equalsIgnoreCase(ext)) if(leftStl != null) { leftGcode = new File(replaceExtension(leftStl.getAbsolutePath(), "gcode")); + Base.logger.log(Level.SEVERE, + "Starting stlToGcode(LEFT)\n"); stlToGcode(leftStl, leftGcode, ToolheadAlias.LEFT, DualStrusionWindow.this.type); } if(rightStl != null) { rightGcode = new File(replaceExtension(rightStl.getAbsolutePath(), "gcode")); + Base.logger.log(Level.SEVERE, + "Starting stlToGcode(RIGHT)\n"); stlToGcode(rightStl, rightGcode, ToolheadAlias.RIGHT, DualStrusionWindow.this.type); } @@ -422,31 +423,105 @@ public void actionPerformed(ActionEvent arg0) { return panel; } - + + private class myListener implements GeneratorListener { + boolean left; + ToolpathGenerator gen; + myListener(boolean x, ToolpathGenerator g) + { + left = x; + gen = g; + } + @Override + public void updateGenerator(GeneratorEvent evt) { + // If config dialog closed and success == false + // config canceled + if("Config Done".equals(evt.getMessage()) && + (!((SkeinforgeGenerator)evt.getSource()).configSuccess)) + { + System.err.println("DualStrusionWindow 466 aborting"); + abort("Skeinforge generation canceled."); + } + } + @Override + public void generationComplete(GeneratorEvent evt) { + if (evt.getCompletion() == Completion.FAILURE) + { + System.err.println("DualStrusionWindow 471 aborting"); + abort("SkeinForge returned FAILURE - Aborting dualstrusion generation"); + return; + } + else if (failure) + { + System.err.println("DualStrusionWindow 477 aborting"); + abort("SkeinForge returned FAILURE - Aborting dualstrusion generation"); + return; + } + if (gen instanceof SkeinforgeGenerator) + { + SkeinforgeGenerator sfg = (SkeinforgeGenerator)gen; + if(left) + { + Base.preferences.put( + "dualstrusionwindow.leftProfile", + sfg.getProfile().getFullPath()); + } + else + { + Base.preferences.put( + "dualstrusionwindow.rightProfile", + sfg.getProfile().getFullPath()); + } + } + completed.countDown(); + if(completed.getCount() == 0) + { + combineGcodes(); + } + } + } + /* * run the selected toolpath generator to convert the stl to gcode, * skeinforge takes special pre- and post- processing */ private void stlToGcode(File stl, File gcode, ToolheadAlias tool, MachineType machineType) { + String lastProfile; + SkeinforgePostProcessor spp = null; + boolean isLeft = (tool == ToolheadAlias.LEFT); try{ if(!gcode.exists()) gcode.createNewFile(); String title = "STL to GCode "; - if(tool == ToolheadAlias.LEFT) + if(isLeft) + { title += "(Left) "; - if(tool == ToolheadAlias.RIGHT) + lastProfile = + Base.preferences.get("dualstrusionwindow.leftProfile", ""); + } + else + { title += "(Right) "; + lastProfile = + Base.preferences.get("dualstrusionwindow.rightProfile", ""); + } title += "Progress"; final JFrame progress = new JFrame(title); - final ToolpathGenerator gen = ToolpathGeneratorFactory.createSelectedGenerator(); + ToolpathGenerator gen = + ToolpathGeneratorFactory.createSelectedGenerator(); if(gen instanceof SkeinforgeGenerator) { - SkeinforgePostProcessor spp = ((SkeinforgeGenerator)gen).getPostProcessor(); - + SkeinforgeGenerator sfg = (SkeinforgeGenerator)gen; + sfg.dualStrusion = true; + if (!lastProfile.isEmpty()) + { + sfg.setProfile(lastProfile); + } + spp = sfg.getPostProcessor(); spp.enableDualstrusion(); spp.setMachineType(machineType); spp.setAddProgressUpdates(false); @@ -455,34 +530,7 @@ private void stlToGcode(File stl, File gcode, ToolheadAlias tool, MachineType ma final Build b = new Build(stl.getAbsolutePath()); final ToolpathGeneratorThread tgt = new ToolpathGeneratorThread(progress, gen, b); - tgt.addListener(new GeneratorListener(){ - @Override - public void updateGenerator(GeneratorEvent evt) { - // If config dialog closed and success == false - // config canceled - if("Config Done".equals(evt.getMessage()) && - (!((SkeinforgeGenerator)evt.getSource()).configSuccess)) - { - abort("Skeinforge generation canceled."); - } - } - - @Override - public void generationComplete(GeneratorEvent evt) { - if(evt.getCompletion() == Completion.FAILURE || failure) - { - abort("SkeinForge returned FAILURE - Aborting dualstrusion generation"); - return; - } - - completed.countDown(); - if(completed.getCount() == 0) - { - combineGcodes(); - } - } - - }); + tgt.addListener(new myListener(isLeft, gen)); if(tool == ToolheadAlias.LEFT) tgt.setDualStrusionSupportFlag(true, 200, 300, stl.getName()); else @@ -531,7 +579,7 @@ private void combineGcodes() return; } - DualStrusionConstruction dsConstruction = new DualStrusionConstruction(leftGcode, rightGcode, startSource, endSource, type, uWipe); + DualStrusionConstruction dsConstruction = new DualStrusionConstruction(leftGcode, rightGcode, type, uWipe); dsConstruction.combine(); dsConstruction.getCombinedFile().writeToFile(dest); diff --git a/src/replicatorg/app/ui/InfoPanel.java b/src/replicatorg/app/ui/InfoPanel.java index 60e2b2523..cbab8b9fd 100644 --- a/src/replicatorg/app/ui/InfoPanel.java +++ b/src/replicatorg/app/ui/InfoPanel.java @@ -5,6 +5,7 @@ import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JLabel; +import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; @@ -39,7 +40,7 @@ public InfoPanel() { infoArea.setBorder(BorderFactory.createEmptyBorder()); infoArea.setBackground(getBackground()); - add(infoArea); + add(new JScrollPane(infoArea)); pack(); infoArea.setText(getMachineInfo()); diff --git a/src/replicatorg/app/ui/MachineStatusPanel.java b/src/replicatorg/app/ui/MachineStatusPanel.java index 28d601342..97bd4219e 100644 --- a/src/replicatorg/app/ui/MachineStatusPanel.java +++ b/src/replicatorg/app/ui/MachineStatusPanel.java @@ -53,27 +53,24 @@ public class MachineStatusPanel extends BGPanel implements MachineListener { MachineStatusPanel() { Font statusFont = Base.getFontPref("status.font","SansSerif,plain,12"); - Font smallFont = statusFont.deriveFont(10f); - smallLabel.setFont(smallFont); - tempLabel.setFont(smallFont); - machineLabel.setFont(smallFont); + Base.logger.info(statusFont.toString()); mainLabel.setFont(statusFont); + machineLabel.setFont(statusFont); + smallLabel.setFont(statusFont); + tempLabel.setFont(statusFont); mainLabel.setText("Not Connected"); - setLayout(new MigLayout("fill,novisualpadding, ins 5 10 5 10")); add(mainLabel, "top, left, growx, split"); add(machineLabel, "top, right, wrap"); add(smallLabel, "bottom, left, growx, split"); add(tempLabel, "bottom, right"); - FontMetrics smallMetrics = this.getFontMetrics(smallFont); FontMetrics bigMetrics = this.getFontMetrics(statusFont); // Height should be ~3 lines - int height = (smallMetrics.getAscent() + smallMetrics.getDescent()) * 2 + - bigMetrics.getAscent() + smallMetrics.getDescent(); + int height = bigMetrics.getHeight() * 3; setMaximumSize(new Dimension(Integer.MAX_VALUE, height)); setMinimumSize(new Dimension(0, height)); - int prefWidth = 80 * smallMetrics.charWidth('n'); + int prefWidth = 80 * bigMetrics.charWidth('n'); setPreferredSize(new Dimension(prefWidth, height)); setBackground(BG_ERROR); } diff --git a/src/replicatorg/app/ui/MainWindow.java b/src/replicatorg/app/ui/MainWindow.java index f6d150512..571a62d7b 100755 --- a/src/replicatorg/app/ui/MainWindow.java +++ b/src/replicatorg/app/ui/MainWindow.java @@ -232,6 +232,8 @@ public class MainWindow extends JFrame implements MRJAboutHandler, MRJQuitHandle public EstimationThread estimationThread; + private Font editorFont = + Base.getFontPref("editor.font","Monospaced,plain,12"); JMenuItem saveMenuItem; JMenuItem saveAsMenuItem; JMenuItem generateItem; @@ -246,7 +248,6 @@ public class MainWindow extends JFrame implements MRJAboutHandler, MRJQuitHandle // JMenuItem editStartItem; // JMenuItem editEndItem; JMenu changeToolheadMenu = new JMenu("Swap Toolhead in .gcode"); - JMenu machineMenu; MachineMenuListener machineMenuListener; @@ -298,7 +299,6 @@ private PreviewPanel getPreviewPanel() { public MainWindow() { super(WINDOW_TITLE); - setLocationByPlatform(true); MRJApplicationUtils.registerAboutHandler(this); MRJApplicationUtils.registerPrefsHandler(this); MRJApplicationUtils.registerQuitHandler(this); @@ -392,9 +392,7 @@ public void windowClosing(WindowEvent e) { splitPane.setDividerSize(dividerSize); } - splitPane.setPreferredSize(new Dimension(600,600)); pane.add(splitPane,"growx,growy,shrinkx,shrinky"); - pack(); // textarea.setTransferHandler(new TransferHandler() { // private static final long serialVersionUID = 2093323078348794384L; @@ -470,6 +468,11 @@ public void restorePreferences() { if (Base.openedAtStartup != null) { handleOpen2(Base.openedAtStartup); } else { + int width = + Base.preferences.getInt("replicatorg.last.window.width", 600); + int height = + Base.preferences.getInt("replicatorg.last.window.height", 600); + setSize(width, height); // last sketch that was in use, or used to launch the app final String prefName = "replicatorg.initialopenbehavior"; int ordinal = Base.preferences.getInt(prefName, InitialOpenBehavior.OPEN_LAST.ordinal()); @@ -535,9 +538,7 @@ public void applyPreferences() { // apply changes to the font size for the editor // TextAreaPainter painter = textarea.getPainter(); - painter.setFont(Base.getFontPref("editor.font","Monospaced,plain,10")); - // Font font = painter.getFont(); - // textarea.getPainter().setFont(new Font("Courier", Font.PLAIN, 36)); + painter.setFont(Base.getFontPref("editor.font","Monospaced,plain,12")); } /** @@ -549,10 +550,8 @@ public void storePreferences() { // window location information Rectangle bounds = getBounds(); - Base.preferences.putInt("last.window.x", bounds.x); - Base.preferences.putInt("last.window.y", bounds.y); - Base.preferences.putInt("last.window.width", bounds.width); - Base.preferences.putInt("last.window.height", bounds.height); + Base.preferences.putInt("replicatorg.last.window.width", bounds.width); + Base.preferences.putInt("replicatorg.last.window.height", bounds.height); // last sketch that was in use // Preferences.set("last.sketch.name", sketchName); @@ -739,12 +738,13 @@ private void reloadSerialMenu() { if (names.isEmpty()) { // Be aware that there is code in machineStateChanged that relies on this string // I know it's a hack, but it works - JMenuItem item = new JMenuItem("No serial ports detected"); + JMenuItem item = + newJMenuItem("No serial ports detected"); item.setEnabled(false); serialMenu.add(item); } serialMenu.addSeparator(); - JMenuItem item = new JMenuItem("Rescan serial ports"); + JMenuItem item = newJMenuItem("Rescan serial ports"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { reloadSerialMenu(); @@ -778,7 +778,7 @@ private void reloadMruMenu() { for (String fileName : mruList) { String entry = Integer.toString(index) + ". " + fileName.substring(fileName.lastIndexOf('/') + 1); - JMenuItem item = new JMenuItem(entry, KeyEvent.VK_0 + index); + JMenuItem item = newJMenuItem(entry, KeyEvent.VK_0 + index); item.addActionListener(new FileOpenActionListener(fileName)); mruMenu.add(item); index = index + 1; @@ -835,7 +835,7 @@ public void actionPerformed(ActionEvent e) { menu.add(buildExamplesMenu()); menu.add(buildScriptsMenu()); - JMenuItem resetParamsItem = new JMenuItem("Reset all preferences"); + JMenuItem resetParamsItem = newJMenuItem("Reset all preferences"); resetParamsItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { resetPreferences(); @@ -876,7 +876,7 @@ protected JMenu buildThingiverseMenu() JMenuItem item; JMenu menu = new JMenu("Thingiverse"); - item = new JMenuItem("What's New?"); + item = newJMenuItem("What's New?"); item.addActionListener( new ActionListener(){ //do bare bones launch @Override @@ -886,7 +886,7 @@ public void actionPerformed(ActionEvent arg0) { }); menu.add(item); - item = new JMenuItem("What's Popular?"); + item = newJMenuItem("What's Popular?"); item.addActionListener( new ActionListener(){ //do bare bones launch @Override @@ -896,7 +896,7 @@ public void actionPerformed(ActionEvent arg0) { }); menu.add(item); - item = new JMenuItem("Dual Extrusion Models!"); + item = newJMenuItem("Dual Extrusion Models!"); item.addActionListener( new ActionListener(){ //do bare bones launch @Override @@ -933,7 +933,7 @@ protected JMenu buildHelpMenu() JMenuItem item; JMenu menu = new JMenu("Help"); - item = new JMenuItem("Offline Documentation"); + item = newJMenuItem("Offline Documentation"); item.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { @@ -952,7 +952,7 @@ public void actionPerformed(ActionEvent arg0) { }); menu.add(item); - item = new JMenuItem("Supported GCodes"); + item = newJMenuItem("Supported GCodes"); item.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { @@ -1009,7 +1009,7 @@ public int compare(JMenuItem o1, JMenuItem o2) { if (m.matches()) { try { FileOpenActionListener l = new FileOpenActionListener(path.getCanonicalPath()); - JMenuItem item = new JMenuItem(path.getName()); + JMenuItem item = newJMenuItem(path.getName()); item.addActionListener(l); return item; } catch (IOException ioe) { return null; } @@ -1024,8 +1024,8 @@ private JMenuItem buildExamplesMenu() { JMenuItem m = buildMenuFromPath(examplesDir,p); if(m == null) { JMenuItem m2 = new JMenu("Examples"); - m2.add(new JMenuItem("No example dirs found.")); - m2.add(new JMenuItem("Check if this dir exists:" + Base.getApplicationFile("examples"))); + m2.add(newJMenuItem("No example dirs found.")); + m2.add(newJMenuItem("Check if this dir exists:" + Base.getApplicationFile("examples"))); return m2; } else { m.setText("Examples"); @@ -1039,8 +1039,8 @@ private JMenuItem buildScriptsMenu() { JMenuItem m = buildMenuFromPath(examplesDir,p); if(m == null) { JMenuItem m2 = new JMenu("Scripts"); - m2.add(new JMenuItem("No scripts found.")); - m2.add(new JMenuItem("Check if this dir exists:" + Base.getApplicationFile("scripts"))); + m2.add(newJMenuItem("No scripts found.")); + m2.add(newJMenuItem("Check if this dir exists:" + Base.getApplicationFile("scripts"))); return m2; } else { m.setText("Scripts"); @@ -1245,10 +1245,13 @@ public void actionPerformed(ActionEvent arg0) { return menu; } - JMenuItem onboardParamsItem = new JMenuItem("Onboard Preferences..."); + JMenuItem onboardParamsItem = + newJMenuItem("Onboard Preferences..."); // JMenuItem toolheadIndexingItem = new JMenuItem("Set Toolhead Index..."); - JMenuItem realtimeControlItem = new JMenuItem("Open real time controls window..."); - JMenuItem infoPanelItem = new JMenuItem("Machine information..."); + JMenuItem realtimeControlItem = + newJMenuItem("Open real time controls window..."); + JMenuItem infoPanelItem = + newJMenuItem("Machine information..."); JMenuItem preheatItem; protected JMenu buildMachineMenu() { @@ -1300,7 +1303,7 @@ public void actionPerformed(ActionEvent arg0) { menu.add(realtimeControlItem); } - item = new JMenuItem("Upload new firmware..."); + item = newJMenuItem("Upload new firmware..."); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { FirmwareUploader.startUploader(MainWindow.this); @@ -1317,7 +1320,7 @@ public void actionPerformed(ActionEvent arg0) { infoPanelItem.setVisible(true); menu.add(infoPanelItem); - preheatItem = new JMenuItem("preheat Not Set"); + preheatItem = newJMenuItem("preheat Not Set"); preheatItem.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { @@ -1701,7 +1704,14 @@ public void actionPerformed(ActionEvent e) { /** * Convenience method, see below. */ - static public JMenuItem newJMenuItem(String title, int what) { + public JMenuItem newJMenuItem(String title) { + return newJMenuItem(title, 0, false); + } + + /** + * Convenience method, see below. + */ + public JMenuItem newJMenuItem(String title, int what) { return newJMenuItem(title, what, false); } @@ -1711,12 +1721,13 @@ static public JMenuItem newJMenuItem(String title, int what) { * that would require a five line helper function just to set the command * key for a menu item. */ - static public JMenuItem newJMenuItem(String title, int what, boolean shift) { + public JMenuItem newJMenuItem(String title, int what, boolean shift) { JMenuItem menuItem = new JMenuItem(title); int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); if (shift) modifiers |= ActionEvent.SHIFT_MASK; - menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers)); + if (what != 0) + menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers)); return menuItem; } @@ -2719,15 +2730,10 @@ public void handleDualStrusion() // this is stuff that DualStrusionConstruction needs, and until there's a better way to get it there... MachineType type = machineLoader.getMachineInterface().getMachineType(); - MutableGCodeSource startCode = - new MutableGCodeSource(machineLoader.getMachineInterface().getModel().getDualstartBookendCode()); - MutableGCodeSource endCode = - new MutableGCodeSource(machineLoader.getMachineInterface().getModel().getEndBookendCode()); - if(getBuild().getCode() != null) - dsw = new DualStrusionWindow(type, startCode, endCode, getBuild().getMainFilePath()); + dsw = new DualStrusionWindow(type, getBuild().getMainFilePath()); else - dsw = new DualStrusionWindow(type, startCode, endCode); + dsw = new DualStrusionWindow(type); dsw.setVisible(true); } @@ -3190,7 +3196,7 @@ public void run() { * Clean up files and store UI preferences on shutdown. This is called by * the shutdown hook and will be run in virtually all shutdown scenarios. * Because it is used in a shutdown hook, there is no reason to call this - * method explicit.y + * method explicitly */ public void onShutdown() { @@ -3305,7 +3311,7 @@ class TextAreaPopup extends JPopupMenu { public TextAreaPopup() { JMenuItem item; - cutItem = new JMenuItem("Cut"); + cutItem = newJMenuItem("Cut"); cutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { textarea.cut(); @@ -3314,7 +3320,7 @@ public void actionPerformed(ActionEvent e) { }); this.add(cutItem); - copyItem = new JMenuItem("Copy"); + copyItem = newJMenuItem("Copy"); copyItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { textarea.copy(); @@ -3322,7 +3328,7 @@ public void actionPerformed(ActionEvent e) { }); this.add(copyItem); - item = new JMenuItem("Paste"); + item = newJMenuItem("Paste"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { textarea.paste(); @@ -3331,7 +3337,7 @@ public void actionPerformed(ActionEvent e) { }); this.add(item); - item = new JMenuItem("Select All"); + item = newJMenuItem("Select All"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { textarea.selectAll(); diff --git a/src/replicatorg/app/ui/PreferencesWindow.java b/src/replicatorg/app/ui/PreferencesWindow.java index 4fdcca8a5..279e1001a 100644 --- a/src/replicatorg/app/ui/PreferencesWindow.java +++ b/src/replicatorg/app/ui/PreferencesWindow.java @@ -58,13 +58,19 @@ public class PreferencesWindow extends JFrame implements GuiConstants { // the calling editor, so updates can be applied MainWindow editor; - JFormattedTextField fontSizeField; + JFormattedTextField statusFontSizeField; + JFormattedTextField editorFontSizeField; + JFormattedTextField consoleFontSizeField; JTextField firmwareUpdateUrlField; JTextField logPathField; - private void showCurrentSettings() { + private void showCurrentSettings() { + Font statusFont = Base.getFontPref("status.font","SansSerif,plain,12"); + statusFontSizeField.setText(String.valueOf(statusFont.getSize())); Font editorFont = Base.getFontPref("editor.font","Monospaced,plain,12"); - fontSizeField.setText(String.valueOf(editorFont.getSize())); + editorFontSizeField.setText(String.valueOf(editorFont.getSize())); + Font consoleFont = Base.getFontPref("console.font","Monospaced,plain,11"); + consoleFontSizeField.setText(String.valueOf(consoleFont.getSize())); String firmwareUrl = Base.preferences.get("replicatorg.updates.url", FirmwareUploader.DEFAULT_UPDATES_URL); firmwareUpdateUrlField.setText(firmwareUrl); String logPath = Base.preferences.get("replicatorg.logpath", ""); @@ -172,7 +178,7 @@ private double confirmTemperature(double target, String limitPrefName, double de public PreferencesWindow(final MachineInterface machine) { super("Preferences"); setResizable(true); - + Image icon = Base.getImage("images/icon.gif", this); setIconImage(icon); @@ -184,11 +190,20 @@ public PreferencesWindow(final MachineInterface machine) { Container content = basic; content.setLayout(new MigLayout("fill")); - content.add(new JLabel("MainWindow font size: "), "split"); - fontSizeField = new JFormattedTextField(Base.getLocalFormat()); - fontSizeField.setColumns(4); - content.add(fontSizeField); - content.add(new JLabel(" (requires restart of ReplicatorG)"), "wrap"); + content.add(new JLabel("Font size for status panel: "), "split"); + statusFontSizeField = new JFormattedTextField(Base.getLocalFormat()); + statusFontSizeField.setColumns(4); + content.add(statusFontSizeField, "wrap"); + + content.add(new JLabel("Font size for gcode window: "), "split"); + editorFontSizeField = new JFormattedTextField(Base.getLocalFormat()); + editorFontSizeField.setColumns(4); + content.add(editorFontSizeField, "wrap"); + + content.add(new JLabel("Font size for console window: "), "split"); + consoleFontSizeField = new JFormattedTextField(Base.getLocalFormat()); + consoleFontSizeField.setColumns(4); + content.add(consoleFontSizeField, "wrap"); boolean checkTempDuringBuild = Base.preferences.getBoolean("build.monitor_temp", true); boolean displaySpeedWarning = Base.preferences.getBoolean("build.speed_warning", true); @@ -531,7 +546,26 @@ public void keyPressed(KeyEvent e) { */ public void applyFrame() { // put each of the settings into the table - String newSizeText = fontSizeField.getText(); + String newSizeText = statusFontSizeField.getText(); + try { + int newSize = Integer.parseInt(newSizeText.trim()); + String fontName = Base.preferences.get("status.font","SansSerif,plain,12"); + if (fontName != null) { + String pieces[] = fontName.split(","); + pieces[2] = String.valueOf(newSize); + StringBuffer buf = new StringBuffer(); + for (String piece : pieces) { + if (buf.length() > 0) buf.append(","); + buf.append(piece); + } + Base.preferences.put("status.font", buf.toString()); + Base.logger.info("put status.font " + buf.toString()); + } + + } catch (Exception e) { + Base.logger.warning("ignoring invalid font size " + newSizeText); + } + newSizeText = editorFontSizeField.getText(); try { int newSize = Integer.parseInt(newSizeText.trim()); String fontName = Base.preferences.get("editor.font","Monospaced,plain,12"); @@ -546,6 +580,24 @@ public void applyFrame() { Base.preferences.put("editor.font", buf.toString()); } + } catch (Exception e) { + Base.logger.warning("ignoring invalid font size " + newSizeText); + } + newSizeText = consoleFontSizeField.getText(); + try { + int newSize = Integer.parseInt(newSizeText.trim()); + String fontName = Base.preferences.get("console.font","Monospaced,plain,11"); + if (fontName != null) { + String pieces[] = fontName.split(","); + pieces[2] = String.valueOf(newSize); + StringBuffer buf = new StringBuffer(); + for (String piece : pieces) { + if (buf.length() > 0) buf.append(","); + buf.append(piece); + } + Base.preferences.put("console.font", buf.toString()); + } + } catch (Exception e) { Base.logger.warning("ignoring invalid font size " + newSizeText); } diff --git a/src/replicatorg/app/util/PythonUtils.java b/src/replicatorg/app/util/PythonUtils.java index 7ed4eb894..646d1c69b 100644 --- a/src/replicatorg/app/util/PythonUtils.java +++ b/src/replicatorg/app/util/PythonUtils.java @@ -121,9 +121,15 @@ public static String getPythonPath(Version minVersion, Version maxVersion) { { String path = Base.preferences.get(PYTON_PATH_PREF, null); if (path != null) { + System.err.println("PYTON_PATH_PREF=" + path); File candidate = new File(path); if (candidate.exists()) { - candidates.add(candidate.getAbsolutePath()); + Version ver = checkVersion(path, minVersion, maxVersion); + if (ver != null) { + pythonPath = path; + pythonVersion = ver; + return path; // just use it + } } } } diff --git a/src/replicatorg/app/util/serial/Serial.java b/src/replicatorg/app/util/serial/Serial.java index d0551f508..1c27254a9 100644 --- a/src/replicatorg/app/util/serial/Serial.java +++ b/src/replicatorg/app/util/serial/Serial.java @@ -43,6 +43,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.logging.Level; import replicatorg.app.Base; import replicatorg.app.exceptions.SerialException; @@ -183,9 +184,11 @@ public Serial(String name) throws SerialException { private CommPortIdentifier findPortIdentifier(String name) { + Base.logger.log(Level.FINEST, "findPortIdentifier(" + name + ")"); Enumeration portList = CommPortIdentifier.getPortIdentifiers(); while (portList.hasMoreElements()) { CommPortIdentifier id = (CommPortIdentifier)portList.nextElement(); + Base.logger.log(Level.FINEST, "Trying " + id.getName()); if (id.getPortType() == CommPortIdentifier.PORT_SERIAL && id.getName().equals(name)) { return id; @@ -196,6 +199,7 @@ private CommPortIdentifier findPortIdentifier(String name) { private void init(String name, int rate, char parity, int data, float stop) throws SerialException { + Base.logger.log(Level.FINEST, "init(" + name + ", " + rate + ")"); // Prepare parameters this.name = name; this.rate = rate; diff --git a/src/replicatorg/drivers/SerialDriver.java b/src/replicatorg/drivers/SerialDriver.java index 562eb33b6..2a5e9fc79 100644 --- a/src/replicatorg/drivers/SerialDriver.java +++ b/src/replicatorg/drivers/SerialDriver.java @@ -74,7 +74,10 @@ public synchronized void openSerial(String portName) { Serial newConnection = null; try { - Base.logger.info("Connecting to machine using serial port: " + portName); + Base.logger.severe("Connecting to machine using serial port: " + portName); + //rpp... + Base.logger.severe("Using baud rate " + rate); + // ... end newConnection = new Serial(portName, rate, parity, databits, stopbits); } catch (SerialException e) { String msg = e.getMessage(); diff --git a/src/replicatorg/machine/builder/Direct.java b/src/replicatorg/machine/builder/Direct.java index f3f2f20b1..afc0e1907 100644 --- a/src/replicatorg/machine/builder/Direct.java +++ b/src/replicatorg/machine/builder/Direct.java @@ -124,6 +124,8 @@ public void runNext() { // Read and process next line if (retry == false) { String line = i.next(); + Base.logger.log(Level.INFO,"Sending Line " + + linesProcessed + ": " + line); linesProcessed++; // Parse a line for the actual machine diff --git a/src/replicatorg/machine/model/ToolheadAlias.java b/src/replicatorg/machine/model/ToolheadAlias.java index f9eaeb397..b300ad229 100644 --- a/src/replicatorg/machine/model/ToolheadAlias.java +++ b/src/replicatorg/machine/model/ToolheadAlias.java @@ -2,7 +2,7 @@ /** * This class represents a lookup system for toolhead info. IT can be used to - * convert variouis ID's from one to another, based on + * convert various ID's from one to another, based on * * Should this be moved into ToolModel? * -Ted diff --git a/src/replicatorg/plugin/toolpath/ToolpathGenerator.java b/src/replicatorg/plugin/toolpath/ToolpathGenerator.java index 030645c2b..7b4ed773c 100644 --- a/src/replicatorg/plugin/toolpath/ToolpathGenerator.java +++ b/src/replicatorg/plugin/toolpath/ToolpathGenerator.java @@ -104,9 +104,20 @@ public void emitUpdate(String message) { } public void emitCompletion(GeneratorListener.Completion completion) { + if (completion == Completion.FAILURE) + { + Base.logger.severe("emitCompletion(Completion.FAILURE)"); + } for (GeneratorListener listener : listeners) { - Base.logger.finest("emitCompletion! sent to " + listener.toString()); - listener.generationComplete(new GeneratorEvent(this, null, completion)); + if (listener == null) + { + Base.logger.severe("null listener"); + } + else + { + Base.logger.finest("emitCompletion! sent to " + listener.toString()); + listener.generationComplete(new GeneratorEvent(this, null, completion)); + } } } diff --git a/src/replicatorg/plugin/toolpath/ToolpathGeneratorThread.java b/src/replicatorg/plugin/toolpath/ToolpathGeneratorThread.java index 3b6ab42f9..191650680 100644 --- a/src/replicatorg/plugin/toolpath/ToolpathGeneratorThread.java +++ b/src/replicatorg/plugin/toolpath/ToolpathGeneratorThread.java @@ -119,21 +119,21 @@ public void run() { }}); } } - Base.logger.info("Beginning toolpath generation."); + Base.logger.info("Beginning toolpath generation. " + name); try { BuildCode code = generator.generateToolpath(); - //Base.logger.severe("Toolpath generation POST generateToolpath!"); + //Base.logger.severe("Toolpath generation POST generateToolpath! " + name); if (code != null) { build.reloadCode(); + //Base.logger.severe("Toolpath generation complete! " + name); generator.emitCompletion(GeneratorListener.Completion.SUCCESS); - //Base.logger.severe("Toolpath generation complete!"); } else { + Base.logger.severe("Toolpath generation failed (returned null)! " + name); generator.emitCompletion(GeneratorListener.Completion.FAILURE); - //Base.logger.severe("Toolpath generation failed!" + code); } } catch (Exception e) { - //Base.logger.severe("Toolpath generation failed!" + e); + Base.logger.severe("Toolpath generation failed! " + name + " " + e); generator.emitCompletion(GeneratorListener.Completion.FAILURE); } finally { if (progressDialog != null) { diff --git a/src/replicatorg/plugin/toolpath/skeinforge/ConfigurationDialog.java b/src/replicatorg/plugin/toolpath/skeinforge/ConfigurationDialog.java index 4cb3d2cfd..e0885a0b6 100644 --- a/src/replicatorg/plugin/toolpath/skeinforge/ConfigurationDialog.java +++ b/src/replicatorg/plugin/toolpath/skeinforge/ConfigurationDialog.java @@ -23,7 +23,6 @@ class ConfigurationDialog extends JDialog { final boolean postProcessToolheadIndex = true; - final String profilePref = "replicatorg.skeinforge.profilePref"; JButton generateButton = new JButton("Generate Gcode"); JButton cancelButton = new JButton("Cancel"); @@ -51,12 +50,23 @@ private void loadList(JComboBox comboBox) { DefaultComboBoxModel model = new DefaultComboBoxModel(); int i=0; int selectedProfile = -1; + String lastSelected; + if (parentGenerator.getProfile() != null) + { + // profile already set by DualStrusion + lastSelected = parentGenerator.getProfile().toString(); + } + else + { + lastSelected = + Base.preferences.get("lastGeneratorProfileSelected","---"); + } for (Profile p : profiles) { ///we display all profiles for all machines. // at MBI customer support's request. model.addElement(p.toString()); - if(p.toString().equals(Base.preferences.get("lastGeneratorProfileSelected","---"))) + if(p.toString().equals(lastSelected)) { Base.logger.fine("Selecting last used element: " + p); /// default select the last profile that matches @@ -193,9 +203,7 @@ protected boolean configureGenerator() Profile p = ProfileUtils.getListedProfile( prefPulldown.getModel(), profiles, idx); - Base.preferences.put("lastGeneratorProfileSelected",p.toString()); - parentGenerator.profile = p.getFullPath(); - SkeinforgeGenerator.setSelectedProfile(p.toString()); + parentGenerator.setProfile(p); return true; } }; diff --git a/src/replicatorg/plugin/toolpath/skeinforge/EditProfileDialog.java b/src/replicatorg/plugin/toolpath/skeinforge/EditProfileDialog.java index 45f21ea7d..7a9885d8b 100644 --- a/src/replicatorg/plugin/toolpath/skeinforge/EditProfileDialog.java +++ b/src/replicatorg/plugin/toolpath/skeinforge/EditProfileDialog.java @@ -37,7 +37,6 @@ class EditProfileDialog extends JDialog { final boolean postProcessToolheadIndex = true; final String manageStr = "Manage profiles..."; - final String profilePref = "replicatorg.skeinforge.profilePref"; JButton editButton = new JButton("Edit..."); JButton duplicateButton = new JButton("Duplicate..."); JButton locateButton = new JButton("Locate..."); @@ -147,9 +146,8 @@ public void mouseClicked(MouseEvent evt) { if (evt.getClickCount() == 2) { // Double-click generates with this profile int idx = list.locationToIndex(evt.getPoint()); Profile p = ProfileUtils.getListedProfile(list.getModel(), profiles, idx); - Base.preferences.put("lastGeneratorProfileSelected",p.toString()); parentGenerator.configSuccess = true; - parentGenerator.profile = p.getFullPath(); + parentGenerator.setProfile(p); setVisible(false); } } @@ -165,9 +163,8 @@ public void keyPressed ( KeyEvent e ) { int idx = prefList.getSelectedIndex(); Base.logger.fine("idx="+idx); Profile p = ProfileUtils.getListedProfile(prefList.getModel(), profiles, idx); - Base.preferences.put("lastGeneratorProfileSelected",p.toString()); parentGenerator.configSuccess = true; - parentGenerator.profile = p.getFullPath(); + parentGenerator.setProfile(p); setVisible(false); } else if(e.getKeyCode() == KeyEvent.VK_ESCAPE) { setVisible(false); diff --git a/src/replicatorg/plugin/toolpath/skeinforge/SkeinforgeGenerator.java b/src/replicatorg/plugin/toolpath/skeinforge/SkeinforgeGenerator.java index e5e6b4475..48a3e2eb8 100644 --- a/src/replicatorg/plugin/toolpath/skeinforge/SkeinforgeGenerator.java +++ b/src/replicatorg/plugin/toolpath/skeinforge/SkeinforgeGenerator.java @@ -41,8 +41,9 @@ public abstract class SkeinforgeGenerator extends ToolpathGenerator { } public boolean configSuccess = false; + public boolean dualStrusion = false; ConfigurationDialog cd; - String profile = null; + private Profile profile = null; List preferences; BuildCode output; @@ -52,6 +53,22 @@ public SkeinforgeGenerator() { postprocess = new SkeinforgePostProcessor(this); } + public void setProfile(Profile p) { + profile = p; + if (!dualStrusion) + { + Base.preferences.put("lastGeneratorProfileSelected",p.toString()); + } + } + + public void setProfile(String s) { + setProfile(new Profile(s)); + } + + public Profile getProfile() { + return profile; + } + public boolean runSanityChecks() { String errors = ""; @@ -75,16 +92,7 @@ public boolean runSanityChecks() { return (result == JOptionPane.OK_OPTION); } - static public String getSelectedProfile() { - String name = Base.preferences.get("replicatorg.skeinforge.profile", ""); - return name; - } - - static public void setSelectedProfile(String name) { - Base.preferences.put("replicatorg.skeinforge.profile", name); - } - - static class Profile implements Comparable { + public static class Profile implements Comparable { private String fullPath; private String name; // targetMachines is a filter that will allow this profile to only be show for specified machines @@ -469,22 +477,39 @@ public Profile duplicateProfile(Profile originalProfile, String newName) { File newProfDir = new File(getUserProfilesDir(), newName); File oldProfDir = new File(originalProfile.getFullPath()); + String oldName = oldProfDir.getName(); try { Base.copyDir(oldProfDir, newProfDir); - Profile newProf = new Profile(newProfDir.getAbsolutePath()); - editProfile(newProf); - return newProf; } catch (IOException ioe) { Base.logger.log(Level.SEVERE, "Couldn't copy directory", ioe); + return null; + } + String subDir = newProfDir.getAbsolutePath() + "/profiles/"; + File f = new File(subDir + "extrusion.csv"); + if (f.exists()) { + try { + String s = Base.loadFile(f); + Base.saveFile(s.replace(oldName, newName), f); + } catch (IOException ioe) { + Base.logger.log(Level.SEVERE, + "Couldn't edit extrusion.csv"); + // We still created the profile, so return it + } } - return null; + subDir = subDir + "extrusion/"; + f = new File(subDir + oldName); + f.renameTo(new File(subDir + newName)); // no IOException possible + Profile newProf = new Profile(newProfDir.getAbsolutePath()); + editProfile(newProf); + return newProf; } public void editProfile(Profile profile) { String[] arguments = { PythonUtils.getPythonPath(), "skeinforge.py", - "-p", profile.getFullPath() }; + "-p", profile.getFullPath()}; ProcessBuilder pb = new ProcessBuilder(arguments); + pb.inheritIO(); File skeinforgeDir = getSkeinforgeDir(); pb.directory(skeinforgeDir); Process process = null; @@ -547,6 +572,7 @@ public void editProfile(Profile profile) { } } catch (IOException ioe) { Base.logger.log(Level.SEVERE, "Could not run skeinforge.", ioe); + Base.logger.log(Level.SEVERE, ioe.toString()); } catch (InterruptedException e) { // We are most likely shutting down, or the process has been // manually aborted. @@ -579,7 +605,7 @@ public BuildCode generateToolpath() { List arguments = new LinkedList(); // The -u makes python output unbuffered. Oh joyous day. String[] baseArguments = { PythonUtils.getPythonPath(), "-u", - "skeinforge.py", "-p", profile }; + "skeinforge.py", "-p", profile.getFullPath() }; for (String arg : baseArguments) { arguments.add(arg); } diff --git a/src/replicatorg/plugin/toolpath/skeinforge/SkeinforgePostProcessor.java b/src/replicatorg/plugin/toolpath/skeinforge/SkeinforgePostProcessor.java index a566f49ea..49ac6a758 100644 --- a/src/replicatorg/plugin/toolpath/skeinforge/SkeinforgePostProcessor.java +++ b/src/replicatorg/plugin/toolpath/skeinforge/SkeinforgePostProcessor.java @@ -372,7 +372,7 @@ public void setToolheadTarget(ToolheadAlias tool) { toolheadTarget = tool; } - + /** * sets the type of machine the code is being generated for * @param type