2015-04-08 15:20:10 -07:00
using MatterHackers.Agg ;
using System ;
2014-02-15 18:06:03 -08:00
using System.Collections.Generic ;
using System.Text ;
namespace MatterHackers.MatterControl.SlicerConfiguration
{
2015-04-08 15:20:10 -07:00
public static class GCodeProcessing
{
2015-04-14 15:27:11 -07:00
private static Dictionary < string , string > replaceWithSettingsStrings = new Dictionary < string , string > ( )
2014-12-10 12:07:06 -08:00
{
2015-04-14 15:27:11 -07:00
// Have a mapping so that MatterSlice while always use a setting that can be set. (the user cannot set first_layer_bedTemperature in MatterSlice)
{ "first_layer_temperature" , "temperature" } ,
{ "temperature" , "temperature" } ,
{ "first_layer_bed_temperature" , "bed_temperature" } ,
2015-05-06 15:01:53 -07:00
{ "bed_temperature" , "bed_temperature" } ,
{ "bed_remove_part_temperature" , "bed_remove_part_temperature" } ,
{ "extruder_wipe_temperature" , "extruder_wipe_temperature" } ,
{ "z_offset" , "z_offset" } ,
{ "retract_length" , "retract_length" } ,
{ "filament_diameter" , "filament_diameter" } ,
{ "first_layer_speed" , "first_layer_speed" } ,
{ "infill_speed" , "infill_speed" } ,
{ "max_fan_speed" , "max_fan_speed" } ,
{ "min_fan_speed" , "min_fan_speed" } ,
{ "min_print_speed" , "min_print_speed" } ,
{ "perimeter_speed" , "perimeter_speed" } ,
{ "retract_speed" , "retract_speed" } ,
{ "support_material_speed" , "support_material_speed" } ,
{ "travel_speed" , "travel_speed" } ,
{ "bridge_fan_speed" , "bridge_fan_speed" } ,
{ "bridge_speed" , "bridge_speed" } ,
{ "raft_print_speed" , "raft_print_speed" } ,
{ "external_perimeter_speed" , "external_perimeter_speed" } ,
2015-04-14 15:27:11 -07:00
} ;
2014-12-10 12:07:06 -08:00
2015-04-08 15:20:10 -07:00
public static string ReplaceMacroValues ( string gcodeWithMacros )
{
2015-04-14 15:27:11 -07:00
foreach ( KeyValuePair < string , string > keyValue in replaceWithSettingsStrings )
2015-04-08 15:20:10 -07:00
{
// do the replacement with {} (curly brackets)
{
2015-04-14 15:27:11 -07:00
string thingToReplace = "{" + "{0}" . FormatWith ( keyValue . Key ) + "}" ;
gcodeWithMacros = gcodeWithMacros . Replace ( thingToReplace , ActiveSliceSettings . Instance . GetActiveValue ( keyValue . Value ) ) ;
2015-04-08 15:20:10 -07:00
}
// do the replacement with [] (square brackets) Slic3r uses only square brackets
{
2015-04-14 15:27:11 -07:00
string thingToReplace = "[" + "{0}" . FormatWith ( keyValue . Key ) + "]" ;
gcodeWithMacros = gcodeWithMacros . Replace ( thingToReplace , ActiveSliceSettings . Instance . GetActiveValue ( keyValue . Value ) ) ;
2015-04-08 15:20:10 -07:00
}
}
2014-02-15 18:06:03 -08:00
2015-04-08 15:20:10 -07:00
return gcodeWithMacros ;
}
}
public class MapItem
{
private string mappedKey ;
private string originalKey ;
public MapItem ( string mappedKey , string originalKey )
{
this . mappedKey = mappedKey ;
this . originalKey = originalKey ;
}
protected static double ParseValueString ( string valueString , double valueOnError = 0 )
{
double value = valueOnError ;
2014-05-09 11:28:55 -07:00
2015-04-08 15:20:10 -07:00
if ( ! double . TryParse ( valueString , out value ) )
{
2014-05-09 14:34:02 -07:00
#if DEBUG
2015-04-08 15:20:10 -07:00
throw new Exception ( "Slicing value is not a double." ) ;
2014-05-09 14:34:02 -07:00
#endif
2015-04-08 15:20:10 -07:00
}
2014-05-09 11:28:55 -07:00
2015-04-08 15:20:10 -07:00
return value ;
}
2014-05-09 11:28:55 -07:00
2015-04-08 15:20:10 -07:00
public static double GetValueForKey ( string originalKey , double valueOnError = 0 )
{
return ParseValueString ( ActiveSliceSettings . Instance . GetActiveValue ( originalKey ) , valueOnError ) ;
}
2014-05-09 11:28:55 -07:00
2015-04-08 15:20:10 -07:00
public string MappedKey { get { return mappedKey ; } }
2014-02-15 18:06:03 -08:00
2015-04-08 15:20:10 -07:00
public string OriginalKey { get { return originalKey ; } }
2014-02-15 18:06:03 -08:00
2015-04-08 15:20:10 -07:00
public string OriginalValue { get { return ActiveSliceSettings . Instance . GetActiveValue ( originalKey ) ; } }
2014-03-20 12:16:04 -07:00
2015-04-08 15:20:10 -07:00
public virtual string MappedValue { get { return OriginalValue ; } }
}
2014-03-20 12:16:04 -07:00
2015-06-11 09:23:29 -07:00
public class MapFirstValue : MapItem
{
public MapFirstValue ( string mappedKey , string originalKey )
: base ( mappedKey , originalKey )
{
}
public override string MappedValue
{
get
{
string mappedValue = base . MappedValue ;
if ( mappedValue . Contains ( "," ) )
{
string [ ] splitValues = mappedValue . Split ( ',' ) ;
return splitValues [ 0 ] ;
}
return mappedValue ;
}
}
}
2015-04-08 15:20:10 -07:00
public class VisibleButNotMappedToEngine : MapItem
{
public override string MappedValue
{
get
{
return null ;
}
}
2014-05-11 06:28:39 -07:00
2015-10-13 13:40:35 -07:00
/// <summary>
/// This key will be show in the editor, but it will not be passed to the actual slicing engine.
/// Some of these values are used in other parts of MatterControl, not slicing, but are held in the slicing data.
/// </summary>
/// <param name="originalKey"></param>
2015-05-01 18:44:43 -07:00
public VisibleButNotMappedToEngine ( string originalKey )
: base ( "" , originalKey )
2015-04-08 15:20:10 -07:00
{
}
}
2014-05-07 15:03:43 -07:00
2015-04-08 15:20:10 -07:00
public class MapStartGCode : InjectGCodeCommands
{
private bool replaceCRs ;
public override string MappedValue
{
get
{
StringBuilder newStartGCode = new StringBuilder ( ) ;
foreach ( string line in PreStartGCode ( SlicingQueue . extrudersUsed ) )
{
newStartGCode . Append ( line + "\n" ) ;
}
newStartGCode . Append ( GCodeProcessing . ReplaceMacroValues ( base . MappedValue ) ) ;
foreach ( string line in PostStartGCode ( SlicingQueue . extrudersUsed ) )
{
newStartGCode . Append ( "\n" ) ;
newStartGCode . Append ( line ) ;
}
if ( replaceCRs )
{
return newStartGCode . ToString ( ) . Replace ( "\n" , "\\n" ) ;
}
return newStartGCode . ToString ( ) ;
}
}
public MapStartGCode ( string mappedKey , string originalKey , bool replaceCRs )
: base ( mappedKey , originalKey )
{
this . replaceCRs = replaceCRs ;
}
public List < string > PreStartGCode ( List < bool > extrudersUsed )
{
string startGCode = ActiveSliceSettings . Instance . GetActiveValue ( "start_gcode" ) ;
string [ ] preStartGCodeLines = startGCode . Split ( new string [ ] { "\\n" } , StringSplitOptions . RemoveEmptyEntries ) ;
List < string > preStartGCode = new List < string > ( ) ;
preStartGCode . Add ( "; automatic settings before start_gcode" ) ;
AddDefaultIfNotPresent ( preStartGCode , "G21" , preStartGCodeLines , "set units to millimeters" ) ;
AddDefaultIfNotPresent ( preStartGCode , "M107" , preStartGCodeLines , "fan off" ) ;
double bed_temperature = ActiveSliceSettings . Instance . BedTemperature ;
if ( bed_temperature > 0 )
{
string setBedTempString = string . Format ( "M190 S{0}" , bed_temperature ) ;
AddDefaultIfNotPresent ( preStartGCode , setBedTempString , preStartGCodeLines , "wait for bed temperature to be reached" ) ;
}
int numberOfHeatedExtruders = 1 ;
if ( ! ActiveSliceSettings . Instance . ExtrudersShareTemperature )
{
numberOfHeatedExtruders = ActiveSliceSettings . Instance . ExtruderCount ;
}
2014-10-13 16:32:54 -07:00
2015-02-19 10:56:54 -08:00
// Start heating all the extruder that we are going to use.
2015-06-17 15:43:37 -07:00
for ( int extruderIndex0Based = 0 ; extruderIndex0Based < numberOfHeatedExtruders ; extruderIndex0Based + + )
2015-04-08 15:20:10 -07:00
{
2015-06-17 15:43:37 -07:00
if ( extrudersUsed . Count > extruderIndex0Based
& & extrudersUsed [ extruderIndex0Based ] )
2015-04-08 15:20:10 -07:00
{
2015-06-17 15:43:37 -07:00
string materialTemperature = ActiveSliceSettings . Instance . GetMaterialValue ( "temperature" , extruderIndex0Based + 1 ) ;
2015-04-08 15:20:10 -07:00
if ( materialTemperature ! = "0" )
{
2015-06-17 15:43:37 -07:00
string setTempString = "M104 T{0} S{1}" . FormatWith ( extruderIndex0Based , materialTemperature ) ;
AddDefaultIfNotPresent ( preStartGCode , setTempString , preStartGCodeLines , string . Format ( "start heating extruder {0}" , extruderIndex0Based + 1 ) ) ;
2015-04-08 15:20:10 -07:00
}
}
}
2014-10-13 17:00:25 -07:00
2015-02-19 10:56:54 -08:00
// If we need to wait for the heaters to heat up before homing then set them to M109 (heat and wait).
if ( ActiveSliceSettings . Instance . GetActiveValue ( "heat_extruder_before_homing" ) = = "1" )
{
2015-06-17 15:43:37 -07:00
for ( int extruderIndex0Based = 0 ; extruderIndex0Based < numberOfHeatedExtruders ; extruderIndex0Based + + )
2015-02-19 10:56:54 -08:00
{
2015-06-17 15:43:37 -07:00
if ( extrudersUsed . Count > extruderIndex0Based
& & extrudersUsed [ extruderIndex0Based ] )
2015-02-19 10:56:54 -08:00
{
2015-06-17 15:43:37 -07:00
string materialTemperature = ActiveSliceSettings . Instance . GetMaterialValue ( "temperature" , extruderIndex0Based + 1 ) ;
2015-02-19 10:56:54 -08:00
if ( materialTemperature ! = "0" )
{
2015-06-17 15:43:37 -07:00
string setTempString = "M109 T{0} S{1}" . FormatWith ( extruderIndex0Based , materialTemperature ) ;
2015-09-21 15:27:32 -07:00
AddDefaultIfNotPresent ( preStartGCode , setTempString , preStartGCodeLines , string . Format ( "wait for extruder {0}" , extruderIndex0Based + 1 ) ) ;
2015-02-19 10:56:54 -08:00
}
}
}
}
2015-04-08 15:20:10 -07:00
SwitchToFirstActiveExtruder ( extrudersUsed , preStartGCodeLines , preStartGCode ) ;
preStartGCode . Add ( "; settings from start_gcode" ) ;
2014-05-07 15:03:43 -07:00
2015-04-08 15:20:10 -07:00
return preStartGCode ;
}
2014-05-07 15:03:43 -07:00
2015-04-08 15:20:10 -07:00
private void SwitchToFirstActiveExtruder ( List < bool > extrudersUsed , string [ ] preStartGCodeLines , List < string > preStartGCode )
{
// make sure we are on the first active extruder
for ( int extruderIndex = 0 ; extruderIndex < extrudersUsed . Count ; extruderIndex + + )
{
if ( extrudersUsed [ extruderIndex ] )
{
// set the active extruder to the first one that will be printing
AddDefaultIfNotPresent ( preStartGCode , "T{0}" . FormatWith ( extruderIndex ) , preStartGCodeLines , "set the active extruder to {0}" . FormatWith ( extruderIndex ) ) ;
break ; // then break so we don't set it to a different ones
}
}
}
public List < string > PostStartGCode ( List < bool > extrudersUsed )
{
string startGCode = ActiveSliceSettings . Instance . GetActiveValue ( "start_gcode" ) ;
string [ ] postStartGCodeLines = startGCode . Split ( new string [ ] { "\\n" } , StringSplitOptions . RemoveEmptyEntries ) ;
2014-05-07 15:03:43 -07:00
2015-04-08 15:20:10 -07:00
List < string > postStartGCode = new List < string > ( ) ;
postStartGCode . Add ( "; automatic settings after start_gcode" ) ;
2014-10-14 16:23:41 -07:00
2015-04-08 15:20:10 -07:00
int numberOfHeatedExtruders = 1 ;
if ( ! ActiveSliceSettings . Instance . ExtrudersShareTemperature )
{
numberOfHeatedExtruders = ActiveSliceSettings . Instance . ExtruderCount ;
}
2014-10-13 17:00:25 -07:00
2015-02-19 10:56:54 -08:00
// don't set the extrudes to heating if we alread waited for them to reach temp
if ( ActiveSliceSettings . Instance . GetActiveValue ( "heat_extruder_before_homing" ) ! = "1" )
{
2015-06-17 15:43:37 -07:00
for ( int extruderIndex0Based = 0 ; extruderIndex0Based < numberOfHeatedExtruders ; extruderIndex0Based + + )
2015-02-19 10:56:54 -08:00
{
2015-06-17 15:43:37 -07:00
if ( extrudersUsed . Count > extruderIndex0Based
& & extrudersUsed [ extruderIndex0Based ] )
2015-02-19 10:56:54 -08:00
{
2015-06-17 15:43:37 -07:00
string materialTemperature = ActiveSliceSettings . Instance . GetMaterialValue ( "temperature" , extruderIndex0Based + 1 ) ;
2015-02-19 10:56:54 -08:00
if ( materialTemperature ! = "0" )
{
2015-06-17 15:43:37 -07:00
string setTempString = "M109 T{0} S{1}" . FormatWith ( extruderIndex0Based , materialTemperature ) ;
2015-09-21 15:27:32 -07:00
AddDefaultIfNotPresent ( postStartGCode , setTempString , postStartGCodeLines , string . Format ( "wait for extruder {0} to reach temperature" , extruderIndex0Based + 1 ) ) ;
2015-02-19 10:56:54 -08:00
}
}
}
}
2014-10-13 16:32:54 -07:00
2015-04-08 15:20:10 -07:00
SwitchToFirstActiveExtruder ( extrudersUsed , postStartGCodeLines , postStartGCode ) ;
AddDefaultIfNotPresent ( postStartGCode , "G90" , postStartGCodeLines , "use absolute coordinates" ) ;
postStartGCode . Add ( string . Format ( "{0} ; {1}" , "G92 E0" , "reset the expected extruder position" ) ) ;
AddDefaultIfNotPresent ( postStartGCode , "M82" , postStartGCodeLines , "use absolute distance for extrusion" ) ;
2014-05-07 15:03:43 -07:00
2015-04-08 15:20:10 -07:00
return postStartGCode ;
}
}
2014-05-07 15:03:43 -07:00
2015-04-08 15:20:10 -07:00
public class MapItemToBool : MapItem
{
public override string MappedValue
{
get
{
if ( base . MappedValue = = "1" )
{
return "True" ;
}
2014-03-21 09:52:24 -07:00
2015-04-08 15:20:10 -07:00
return "False" ;
}
}
2014-03-24 12:21:21 -07:00
2015-04-08 15:20:10 -07:00
public MapItemToBool ( string mappedKey , string originalKey )
: base ( mappedKey , originalKey )
{
}
}
2014-03-24 12:21:21 -07:00
2015-06-11 09:23:29 -07:00
public class ScaledSingleNumber : MapFirstValue
2015-04-08 15:20:10 -07:00
{
internal double scale ;
public override string MappedValue
{
get
{
double ratio = 0 ;
if ( OriginalValue . Contains ( "%" ) )
{
string withoutPercent = OriginalValue . Replace ( "%" , "" ) ;
ratio = MapItem . ParseValueString ( withoutPercent ) / 100.0 ;
}
else
{
ratio = MapItem . ParseValueString ( base . MappedValue ) ;
}
return ( ratio * scale ) . ToString ( ) ;
}
}
internal ScaledSingleNumber ( string mappedKey , string originalKey , double scale = 1 )
: base ( mappedKey , originalKey )
{
this . scale = scale ;
}
}
public class InjectGCodeCommands : ConvertCRs
{
public InjectGCodeCommands ( string mappedKey , string originalKey )
: base ( mappedKey , originalKey )
{
}
protected void AddDefaultIfNotPresent ( List < string > linesAdded , string commandToAdd , string [ ] linesToCheckIfAlreadyPresent , string comment )
{
string command = commandToAdd . Split ( ' ' ) [ 0 ] . Trim ( ) ;
bool foundCommand = false ;
foreach ( string line in linesToCheckIfAlreadyPresent )
{
if ( line . StartsWith ( command ) )
{
foundCommand = true ;
break ;
}
}
if ( ! foundCommand )
{
linesAdded . Add ( string . Format ( "{0} ; {1}" , commandToAdd , comment ) ) ;
}
}
}
public class ConvertCRs : MapItem
{
public override string MappedValue
{
get
{
string actualCRs = base . MappedValue . Replace ( "\\n" , "\n" ) ;
return actualCRs ;
}
}
public ConvertCRs ( string mappedKey , string originalKey )
: base ( mappedKey , originalKey )
{
}
}
2015-05-01 18:44:43 -07:00
public class AsCountOrDistance : MapItem
2015-04-24 13:09:25 -07:00
{
2015-05-06 15:01:53 -07:00
private string keyToUseAsDenominatorForCount ;
2015-05-01 18:44:43 -07:00
public AsCountOrDistance ( string mappedKey , string originalKey , string keyToUseAsDenominatorForCount )
2015-04-24 13:09:25 -07:00
: base ( mappedKey , originalKey )
{
2015-05-01 18:44:43 -07:00
this . keyToUseAsDenominatorForCount = keyToUseAsDenominatorForCount ;
2015-04-24 13:09:25 -07:00
}
public override string MappedValue
{
get
{
if ( OriginalValue . Contains ( "mm" ) )
{
string withoutMm = OriginalValue . Replace ( "mm" , "" ) ;
2015-05-01 18:44:43 -07:00
string distanceString = ActiveSliceSettings . Instance . GetActiveValue ( keyToUseAsDenominatorForCount ) ;
double denominator = MapItem . ParseValueString ( distanceString , 1 ) ;
int layers = ( int ) ( MapItem . ParseValueString ( withoutMm ) / denominator + . 5 ) ;
2015-04-24 13:09:25 -07:00
return layers . ToString ( ) ;
}
return base . MappedValue ;
}
}
}
2015-06-09 11:30:14 -07:00
public class AsPercentOfReferenceOrDirect : MapItem
2015-04-08 15:20:10 -07:00
{
2015-06-09 11:30:14 -07:00
string originalReference ;
double scale ;
2015-04-08 15:20:10 -07:00
public override string MappedValue
{
get
{
2015-06-09 11:30:14 -07:00
double finalValue = 0 ;
2015-04-08 15:20:10 -07:00
if ( OriginalValue . Contains ( "%" ) )
{
string withoutPercent = OriginalValue . Replace ( "%" , "" ) ;
double ratio = MapItem . ParseValueString ( withoutPercent ) / 100.0 ;
string originalReferenceString = ActiveSliceSettings . Instance . GetActiveValue ( originalReference ) ;
double valueToModify = MapItem . ParseValueString ( originalReferenceString ) ;
2015-06-09 11:30:14 -07:00
finalValue = valueToModify * ratio ;
}
else
{
finalValue = MapItem . ParseValueString ( OriginalValue ) ;
2015-04-08 15:20:10 -07:00
}
2015-06-09 11:30:14 -07:00
if ( finalValue = = 0 )
{
finalValue = MapItem . ParseValueString ( ActiveSliceSettings . Instance . GetActiveValue ( originalReference ) ) ;
}
finalValue * = scale ;
return finalValue . ToString ( ) ;
2015-04-08 15:20:10 -07:00
}
}
public AsPercentOfReferenceOrDirect ( string mappedKey , string originalKey , string originalReference , double scale = 1 )
2015-06-09 11:30:14 -07:00
: base ( mappedKey , originalKey )
2015-04-08 15:20:10 -07:00
{
2015-06-09 11:30:14 -07:00
this . scale = scale ;
2015-04-08 15:20:10 -07:00
this . originalReference = originalReference ;
}
}
}