Add gradientspace gsSlicer
This commit is contained in:
parent
9523ae320f
commit
03cc686292
15 changed files with 1861 additions and 2 deletions
11
.gitmodules
vendored
11
.gitmodules
vendored
|
|
@ -3,4 +3,13 @@
|
|||
url = https://github.com/MatterHackers/MatterSlice.git
|
||||
[submodule "Submodules/agg-sharp"]
|
||||
path = Submodules/agg-sharp
|
||||
url = https://github.com/MatterHackers/agg-sharp.git
|
||||
url = https://github.com/MatterHackers/agg-sharp.git
|
||||
[submodule "Submodules/geometry3Sharp"]
|
||||
path = Submodules/geometry3Sharp
|
||||
url = https://github.com/MatterHackers/geometry3Sharp
|
||||
[submodule "Submodules/gsGCode"]
|
||||
path = Submodules/gsGCode
|
||||
url = https://github.com/MatterHackers/gsGCode
|
||||
[submodule "Submodules/gsSlicer"]
|
||||
path = Submodules/gsSlicer
|
||||
url = https://github.com/MatterHackers/gsSlicer
|
||||
|
|
|
|||
158
MatterHackers.gsSlicer/BasicSlicer.cs
Normal file
158
MatterHackers.gsSlicer/BasicSlicer.cs
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
Copyright (c) 2019, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using cotangent;
|
||||
using g3;
|
||||
using gs;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MatterControl.SlicerConfiguration;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.gsBundle
|
||||
{
|
||||
public class BasicSlicer : IObjectSlicer
|
||||
{
|
||||
public async Task<bool> Slice(IObject3D object3D, IEnumerable<IObject3D> printableItems, PrinterSettings printerSettings, string filePath, IProgress<ProgressStatus> progressReporter, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
using (var outputStream = File.OpenWrite(filePath))
|
||||
{
|
||||
var sourceMeshes = new List<DMesh3>();
|
||||
|
||||
foreach (var item in object3D.VisibleMeshes().Where(d => d.MeshPath != null))
|
||||
{
|
||||
string sourceFilePath = await item.ResolveFilePath(null, cancellationToken);
|
||||
|
||||
// Load Mesh
|
||||
if (File.Exists(sourceFilePath))
|
||||
{
|
||||
var mesh = StandardMeshReader.ReadMesh(sourceFilePath);
|
||||
if (mesh != null)
|
||||
{
|
||||
sourceMeshes.Add(mesh);
|
||||
}
|
||||
|
||||
var printCenter = printerSettings.GetValue<Vector2>(SettingsKey.print_center);
|
||||
ApplyTransform(mesh, item.WorldMatrix(), printCenter);
|
||||
}
|
||||
}
|
||||
|
||||
PrintSettings settings = LoadSettingsForPrinter(printerSettings);
|
||||
|
||||
// Construct slicer
|
||||
var slicer = new GeometrySlicer();
|
||||
slicer.SliceMeshes(sourceMeshes, settings);
|
||||
|
||||
bool valid = slicer.ExtractResultsIfValid(out PrintMeshAssembly meshes, out PlanarSliceStack slices);
|
||||
|
||||
// Construct GCode generator
|
||||
var pathGenerator = new ToolpathGenerator();
|
||||
pathGenerator.CreateToolPaths(meshes, slices, settings);
|
||||
|
||||
// Write GCode file
|
||||
var gcodeWriter = new StandardGCodeWriter();
|
||||
|
||||
var streamWriter = new StreamWriter(outputStream);
|
||||
|
||||
gcodeWriter.WriteFile(pathGenerator.CurrentGCode, streamWriter);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static PrintSettings LoadSettingsForPrinter(PrinterSettings printerSettings)
|
||||
{
|
||||
var ss = new MatterHackersPrinter(printerSettings);
|
||||
|
||||
var settings = new PrintSettings();
|
||||
settings.UpdateFromSettings(ss);
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
// Modeled after FlipLeftRightCoordSystems and ConvertYUpToZUp examples
|
||||
public static void ApplyTransform(IDeformableMesh mesh, Matrix4X4 matrix, Vector2 printCenter)
|
||||
{
|
||||
int NV = mesh.MaxVertexID;
|
||||
for (int vid = 0; vid < NV; ++vid)
|
||||
{
|
||||
if (mesh.IsVertex(vid))
|
||||
{
|
||||
Vector3d v = mesh.GetVertex(vid);
|
||||
|
||||
// Transform point to MatterControl bed translation
|
||||
var vec3 = new Vector3(v.x, v.y, v.z);
|
||||
var transformed = vec3.Transform(matrix);
|
||||
|
||||
// Update and reset
|
||||
v.x = transformed.X - printCenter.X;
|
||||
v.y = transformed.Y - printCenter.Y;
|
||||
v.z = transformed.Z;
|
||||
|
||||
mesh.SetVertex(vid, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, ExportField> Exports { get; } = new Dictionary<string, ExportField>()
|
||||
{
|
||||
[SettingsKey.external_perimeter_speed] = new ExportField(""),
|
||||
[SettingsKey.make] = new ExportField(""),
|
||||
[SettingsKey.model] = new ExportField(""),
|
||||
[SettingsKey.build_height] = new ExportField(""),
|
||||
[SettingsKey.nozzle_diameter] = new ExportField(""),
|
||||
[SettingsKey.filament_diameter] = new ExportField(""),
|
||||
[SettingsKey.has_heated_bed] = new ExportField(""),
|
||||
[SettingsKey.has_hardware_leveling] = new ExportField(""),
|
||||
[SettingsKey.layer_height] = new ExportField(""),
|
||||
[SettingsKey.temperature1] = new ExportField(""),
|
||||
[SettingsKey.bed_temperature] = new ExportField(""),
|
||||
[SettingsKey.retract_length] = new ExportField(""),
|
||||
[SettingsKey.retract_speed] = new ExportField(""),
|
||||
[SettingsKey.travel_speed] = new ExportField(""),
|
||||
[SettingsKey.first_layer_speed] = new ExportField(""),
|
||||
[SettingsKey.bottom_solid_layers] = new ExportField(""),
|
||||
[SettingsKey.top_solid_layers] = new ExportField("")
|
||||
};
|
||||
|
||||
public bool ValidateFile(string filePath)
|
||||
{
|
||||
// TODO: Implement solution
|
||||
System.Diagnostics.Debugger.Break();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
MatterHackers.gsSlicer/MatterControl.gsSlicer.csproj
Normal file
29
MatterHackers.gsSlicer/MatterControl.gsSlicer.csproj
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<OutputPath>F:\Sources\mccentral\MatterControl\bin\Debug</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MatterControl.Common\MatterControl.Common.csproj" />
|
||||
<ProjectReference Include="..\MatterControl.Printing\MatterControl.Printing.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\agg\Agg.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\DataConverters3D\DataConverters3D.csproj" />
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\VectorMath\VectorMath.csproj" />
|
||||
<ProjectReference Include="..\Submodules\geometry3Sharp\geometry3Sharp.csproj" />
|
||||
<ProjectReference Include="..\Submodules\gsGCode\gsGCode.csproj" />
|
||||
<ProjectReference Include="..\Submodules\gsGeometry\gsGeometry.csproj" />
|
||||
<ProjectReference Include="..\Submodules\gsSlicerPro\gsSlicerPro.csproj" />
|
||||
<ProjectReference Include="..\Submodules\gsSlicer\gsSlicer.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
129
MatterHackers.gsSlicer/MatterHackersPrinter.cs
Normal file
129
MatterHackers.gsSlicer/MatterHackersPrinter.cs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
Copyright (c) 2019, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using gs;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.MatterControl.SlicerConfiguration;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.gsBundle
|
||||
{
|
||||
public class MatterHackersPrinter : GenericRepRapSettings
|
||||
{
|
||||
public MatterHackersPrinter(PrinterSettings settings)
|
||||
{
|
||||
string make = settings.GetValue<string>(SettingsKey.make);
|
||||
string model = settings.GetValue<string>(SettingsKey.model);
|
||||
|
||||
var printCenter = settings.GetValue<Vector2>(SettingsKey.print_center);
|
||||
var bedSize = settings.GetValue<Vector2>(SettingsKey.bed_size);
|
||||
|
||||
machineInfo = new FFFMachineInfo()
|
||||
{
|
||||
ManufacturerName = make,
|
||||
ManufacturerUUID = agg_basics.GetLongHashCode(make).ToString(),
|
||||
ModelIdentifier = model,
|
||||
ModelUUID = agg_basics.GetLongHashCode(model).ToString(),
|
||||
Class = MachineClass.PlasticFFFPrinter,
|
||||
|
||||
BedSizeXMM = (int)settings.BedBounds.Width,
|
||||
BedSizeYMM = (int)settings.BedBounds.Height,
|
||||
// BedSizeZMM = settings.GetValue<int>(SettingsKey.build_height),
|
||||
MaxHeightMM = settings.GetValue<int>(SettingsKey.build_height),
|
||||
|
||||
NozzleDiamMM = settings.GetValue<double>(SettingsKey.nozzle_diameter),
|
||||
FilamentDiamMM = settings.GetValue<double>(SettingsKey.filament_diameter),
|
||||
|
||||
// Set bed origin factors based on printer center/bedsize
|
||||
BedOriginFactorX = printCenter.X / bedSize.X,
|
||||
BedOriginFactorY = printCenter.Y / bedSize.Y,
|
||||
|
||||
HasHeatedBed = settings.GetValue<bool>(SettingsKey.has_heated_bed),
|
||||
HasAutoBedLeveling = settings.GetValue<bool>(SettingsKey.has_hardware_leveling),
|
||||
EnableAutoBedLeveling = false,
|
||||
|
||||
// TODO: Consider how to adapt and/or update for MatterControl printers
|
||||
MaxExtruderTempC = 250,
|
||||
MaxBedTempC = 80,
|
||||
|
||||
MaxExtrudeSpeedMMM = 80 * 60,
|
||||
MaxTravelSpeedMMM = 120 * 60,
|
||||
MaxZTravelSpeedMMM = 100 * 60,
|
||||
MaxRetractSpeedMMM = 45 * 60,
|
||||
MinLayerHeightMM = 0.05,
|
||||
MaxLayerHeightMM = 0.3,
|
||||
};
|
||||
|
||||
LayerHeightMM = settings.GetValue<double>(SettingsKey.layer_height);
|
||||
|
||||
ExtruderTempC = (int)settings.GetValue<double>(SettingsKey.temperature1);
|
||||
HeatedBedTempC = (int)settings.GetValue<double>(SettingsKey.bed_temperature);
|
||||
|
||||
RoofLayers = settings.GetValue<int>(SettingsKey.top_solid_layers);
|
||||
FloorLayers = settings.GetValue<int>(SettingsKey.bottom_solid_layers);
|
||||
|
||||
SolidFillNozzleDiamStepX = 1.0;
|
||||
RetractDistanceMM = settings.GetValue<double>(SettingsKey.retract_length);
|
||||
|
||||
RetractSpeed = settings.GetValue<double>(SettingsKey.retract_speed) * 60;
|
||||
ZTravelSpeed = settings.Helpers.GetMovementSpeeds()["z"] * 60;
|
||||
RapidTravelSpeed = settings.GetValue<double>(SettingsKey.travel_speed) * 60;
|
||||
CarefulExtrudeSpeed = settings.GetValue<double>(SettingsKey.first_layer_speed) * 60;
|
||||
RapidExtrudeSpeed = Machine.MaxExtrudeSpeedMMM;
|
||||
|
||||
// Looks like fractional of perimeter speed
|
||||
var outerSpeed = settings.GetValue<double>(SettingsKey.external_perimeter_speed);
|
||||
var innerSpeed = settings.GetValue<double>(SettingsKey.external_perimeter_speed);
|
||||
|
||||
OuterPerimeterSpeedX = outerSpeed / innerSpeed;
|
||||
}
|
||||
|
||||
public override AssemblerFactoryF AssemblerType()
|
||||
{
|
||||
return (GCodeBuilder builder, SingleMaterialFFFSettings settings) =>
|
||||
{
|
||||
return new RepRapAssembler(builder, settings)
|
||||
{
|
||||
HeaderCustomizerF = HeaderCustomF
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
protected void HeaderCustomF(RepRapAssembler.HeaderState state, GCodeBuilder Builder)
|
||||
{
|
||||
if (state == RepRapAssembler.HeaderState.BeforePrime)
|
||||
{
|
||||
if (Machine.HasAutoBedLeveling && Machine.EnableAutoBedLeveling)
|
||||
{
|
||||
Builder.BeginGLine(29, "auto-level bed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
MatterHackers.gsSlicer/Slicer/CoreTypes.cs
Normal file
70
MatterHackers.gsSlicer/Slicer/CoreTypes.cs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace cotangent
|
||||
{
|
||||
|
||||
|
||||
public enum LineWidthType
|
||||
{
|
||||
World,
|
||||
Pixel
|
||||
}
|
||||
|
||||
|
||||
public enum FrameType
|
||||
{
|
||||
LocalFrame = 0,
|
||||
WorldFrame = 1
|
||||
};
|
||||
|
||||
|
||||
public enum UpDirection
|
||||
{
|
||||
ZUp = 0,
|
||||
YUp = 1
|
||||
}
|
||||
|
||||
|
||||
public enum PivotLocation
|
||||
{
|
||||
Center = 0,
|
||||
BaseCenter = 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// will/may be called per-frame to give a chance to do something with shortcut keys
|
||||
// return true to indicate that key was handled, ie "capture" it
|
||||
public interface IShortcutKeyHandler
|
||||
{
|
||||
bool HandleShortcuts();
|
||||
}
|
||||
|
||||
|
||||
public interface ITextEntryTarget
|
||||
{
|
||||
bool ConsumeAllInput();
|
||||
bool OnBeginTextEntry();
|
||||
bool OnEndTextEntry();
|
||||
bool OnBackspace();
|
||||
bool OnDelete();
|
||||
bool OnReturn();
|
||||
bool OnEscape();
|
||||
bool OnLeftArrow();
|
||||
bool OnRightArrow();
|
||||
bool OnCharacters(string s);
|
||||
}
|
||||
|
||||
|
||||
public enum CameraInteractionState
|
||||
{
|
||||
BeginCameraAction,
|
||||
EndCameraAction,
|
||||
Ignore
|
||||
}
|
||||
|
||||
}
|
||||
292
MatterHackers.gsSlicer/Slicer/GeometrySlicer.cs
Normal file
292
MatterHackers.gsSlicer/Slicer/GeometrySlicer.cs
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using g3;
|
||||
using gs;
|
||||
using gs.info;
|
||||
|
||||
namespace cotangent
|
||||
{
|
||||
/// <summary>
|
||||
/// Auto-compute slicing of current CC.PrintMeshes
|
||||
///
|
||||
/// [TODO]
|
||||
/// - be smarter about polylines?
|
||||
/// - don't necessarily always need to discard SlicerMeshes, for example if only
|
||||
/// slicing params changed, we can avoid copy (maybe irrelevant though)
|
||||
/// </summary>
|
||||
public class GeometrySlicer
|
||||
{
|
||||
PrintMeshAssembly SlicerMeshes;
|
||||
PlanarSliceStack SliceSet;
|
||||
bool SliceStackValid;
|
||||
object data_lock = new object();
|
||||
|
||||
bool show_slice_polylines = false;
|
||||
public bool ShowSlicePolylines
|
||||
{
|
||||
get { return show_slice_polylines; }
|
||||
set { set_slice_polylines_visible(value); }
|
||||
}
|
||||
|
||||
public delegate void SlicingStateChangeHandler();
|
||||
public event SlicingStateChangeHandler SlicingInvalidatedEvent;
|
||||
public event SlicingStateChangeHandler SlicingUpdatedEvent;
|
||||
|
||||
// public event SlicingProgressHandler SlicingProgressEvent;
|
||||
|
||||
public bool PauseSlicing = false;
|
||||
|
||||
public GeometrySlicer()
|
||||
{
|
||||
InvalidateSlicing();
|
||||
}
|
||||
|
||||
public bool IsResultValid()
|
||||
{
|
||||
bool valid = false;
|
||||
lock (data_lock)
|
||||
{
|
||||
valid = SliceStackValid;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
public bool ExtractResultsIfValid(out PrintMeshAssembly printMeshes, out PlanarSliceStack slices)
|
||||
{
|
||||
bool valid = false;
|
||||
lock (data_lock)
|
||||
{
|
||||
printMeshes = SlicerMeshes;
|
||||
slices = SliceSet;
|
||||
valid = SliceStackValid;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
public void InvalidateSlicing()
|
||||
{
|
||||
//cancel_active_compute();
|
||||
|
||||
lock (data_lock)
|
||||
{
|
||||
SlicerMeshes = null;
|
||||
SliceSet = null;
|
||||
SliceStackValid = false;
|
||||
}
|
||||
|
||||
// discard_slice_polylines();
|
||||
|
||||
}
|
||||
|
||||
public void SliceMeshes(List<DMesh3> sourceMeshes, PrintSettings printSettings)
|
||||
{
|
||||
SliceStackValid = false;
|
||||
|
||||
try
|
||||
{
|
||||
var sliceTask = new SliceTask();
|
||||
sliceTask.meshCopies = sourceMeshes;
|
||||
sliceTask.Compute(printSettings);
|
||||
|
||||
SlicerMeshes = sliceTask.MeshAssembly;
|
||||
SliceSet = sliceTask.SliceStack;
|
||||
SliceStackValid = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
float last_spawn_time = 0;
|
||||
|
||||
SliceTask active_compute;
|
||||
object active_compute_lock = new object();
|
||||
|
||||
class SliceTask
|
||||
{
|
||||
// input data
|
||||
public Frame3f[] meshToScene;
|
||||
public Vector3f[] localScale;
|
||||
public List<DMesh3> meshCopies { get; set; }
|
||||
public PrintMeshSettings[] meshSettings;
|
||||
|
||||
// computed data
|
||||
public bool Finished;
|
||||
public bool Success;
|
||||
public PrintMeshAssembly MeshAssembly;
|
||||
public PlanarSliceStack SliceStack;
|
||||
|
||||
// internal
|
||||
MeshPlanarSlicerPro slicer;
|
||||
|
||||
public SliceTask()
|
||||
{
|
||||
Finished = false;
|
||||
Success = false;
|
||||
}
|
||||
|
||||
public void Compute(PrintSettings printSettings)
|
||||
{
|
||||
int N = meshCopies.Count();
|
||||
|
||||
slicer = new MeshPlanarSlicerPro()
|
||||
{
|
||||
LayerHeightMM = printSettings.LayerHeightMM,
|
||||
// [RMS] 1.5 here is a hack. If we don't leave a bit of space then often the filament gets squeezed right at
|
||||
// inside/outside transitions, which is bad. Need a better way to handle.
|
||||
OpenPathDefaultWidthMM = printSettings.NozzleDiameterMM * 1.5,
|
||||
SetMinZValue = 0,
|
||||
SliceFactoryF = PlanarSlicePro.FactoryF
|
||||
};
|
||||
|
||||
if (printSettings.OpenMode == PrintSettings.OpenMeshMode.Clipped)
|
||||
slicer.DefaultOpenPathMode = PrintMeshOptions.OpenPathsModes.Clipped;
|
||||
else if (printSettings.OpenMode == PrintSettings.OpenMeshMode.Embedded)
|
||||
slicer.DefaultOpenPathMode = PrintMeshOptions.OpenPathsModes.Embedded;
|
||||
else if (printSettings.OpenMode == PrintSettings.OpenMeshMode.Ignored)
|
||||
slicer.DefaultOpenPathMode = PrintMeshOptions.OpenPathsModes.Ignored;
|
||||
|
||||
if (printSettings.StartLayers > 0)
|
||||
{
|
||||
int start_layers = printSettings.StartLayers;
|
||||
double std_layer_height = printSettings.LayerHeightMM;
|
||||
double start_layer_height = printSettings.StartLayerHeightMM;
|
||||
slicer.LayerHeightF = (layer_i) =>
|
||||
{
|
||||
return (layer_i < start_layers) ? start_layer_height : std_layer_height;
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
MeshAssembly = new PrintMeshAssembly();
|
||||
|
||||
for (int k = 0; k < N; ++k)
|
||||
{
|
||||
DMesh3 mesh = meshCopies[k];
|
||||
//Frame3f mapF = meshToScene[k];
|
||||
PrintMeshSettings settings = new PrintMeshSettings();
|
||||
|
||||
var options = new PrintMeshOptions
|
||||
{
|
||||
IsSupport = (settings.ObjectType == PrintMeshSettings.ObjectTypes.Support),
|
||||
IsCavity = (settings.ObjectType == PrintMeshSettings.ObjectTypes.Cavity),
|
||||
IsCropRegion = (settings.ObjectType == PrintMeshSettings.ObjectTypes.CropRegion),
|
||||
IsOpen = settings.OuterShellOnly,
|
||||
OpenPathMode = PrintMeshSettings.Convert(settings.OpenMeshMode),
|
||||
Extended = new ExtendedPrintMeshOptions()
|
||||
{
|
||||
ClearanceXY = settings.Clearance,
|
||||
OffsetXY = settings.OffsetXY
|
||||
}
|
||||
};
|
||||
|
||||
//Vector3f scale = localScale[k];
|
||||
//MeshTransforms.Scale(mesh, scale.x, scale.y, scale.z);
|
||||
//MeshTransforms.FromFrame(mesh, mapF);
|
||||
//MeshTransforms.FlipLeftRightCoordSystems(mesh);
|
||||
//MeshTransforms.ConvertYUpToZUp(mesh);
|
||||
|
||||
var decomposer = new MeshAssembly(mesh)
|
||||
{
|
||||
HasNoVoids = settings.NoVoids
|
||||
};
|
||||
decomposer.Decompose();
|
||||
|
||||
MeshAssembly.AddMeshes(decomposer.ClosedSolids, options);
|
||||
|
||||
PrintMeshOptions openOptions = options.Clone();
|
||||
MeshAssembly.AddMeshes(decomposer.OpenMeshes, openOptions);
|
||||
}
|
||||
|
||||
if (slicer.Add(MeshAssembly) == false)
|
||||
throw new Exception("error adding PrintMeshAssembly to Slicer!!");
|
||||
|
||||
// set clip box
|
||||
Box2d clip_box = new Box2d(
|
||||
Vector2d.Zero,
|
||||
new Vector2d(printSettings.BedSizeXMM / 2, printSettings.BedSizeYMM / 2));
|
||||
|
||||
slicer.ValidRegions = new List<GeneralPolygon2d>() {
|
||||
new GeneralPolygon2d(new Polygon2d(clip_box.ComputeVertices()))
|
||||
};
|
||||
|
||||
SliceStack = slicer.Compute();
|
||||
|
||||
Success = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//DebugUtil.Log("GeometrySlicer.Compute: exception: " + e.Message);
|
||||
System.Diagnostics.Debugger.Break();
|
||||
Success = false;
|
||||
}
|
||||
|
||||
Finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
void set_slice_polylines_visible(bool bSet)
|
||||
{
|
||||
if (bSet == show_slice_polylines)
|
||||
return;
|
||||
|
||||
compute_slice_polylines();
|
||||
show_slice_polylines = true;
|
||||
}
|
||||
|
||||
void compute_slice_polylines()
|
||||
{
|
||||
// fMaterial mat1 = MaterialUtil.CreateFlatMaterialF(Colorf.Black);
|
||||
// fMaterial mat2 = MaterialUtil.CreateFlatMaterialF(Colorf.BlueMetal);
|
||||
|
||||
// [TODO] do we need to hold data_lock here? seems like no since main thread is blocked,
|
||||
// then it would never be the case that we are setting SliceSet = null
|
||||
|
||||
// create geometry
|
||||
int slice_i = 0;
|
||||
//SlicePolylines = new List<fPolylineGameObject>();
|
||||
|
||||
foreach (PlanarSlice slice in SliceSet.Slices)
|
||||
{
|
||||
//DebugUtil.Log(2, "Slice has {0} solids", slice.Solids.Count);
|
||||
Colorf slice_color = (slice_i % 2 == 0) ? Colorf.Black : Colorf.BlueMetal;
|
||||
// fMaterial slice_mat = (slice_i % 2 == 0) ? mat1 : mat2;
|
||||
slice_i++;
|
||||
foreach (GeneralPolygon2d poly in slice.Solids)
|
||||
{
|
||||
List<Vector3f> polyLine = new List<Vector3f>();
|
||||
for (int pi = 0; pi <= poly.Outer.VertexCount; ++pi)
|
||||
{
|
||||
int i = pi % poly.Outer.VertexCount;
|
||||
Vector2d v2 = poly.Outer[i];
|
||||
Vector2d n2 = poly.Outer.GetTangent(i).Perp;
|
||||
|
||||
Vector3d v3 = new Vector3d(v2.x, v2.y, slice.Z);
|
||||
v3 = MeshTransforms.ConvertZUpToYUp(v3);
|
||||
v3 = MeshTransforms.FlipLeftRightCoordSystems(v3);
|
||||
Vector3d n3 = MeshTransforms.ConvertZUpToYUp(new Vector3d(n2.x, n2.y, 0));
|
||||
n3 = MeshTransforms.FlipLeftRightCoordSystems(n3);
|
||||
n3.Normalize();
|
||||
v3 += 0.1f * n3;
|
||||
|
||||
polyLine.Add((Vector3f)v3);
|
||||
}
|
||||
|
||||
// Do something with polyline....
|
||||
Console.WriteLine(polyLine);
|
||||
|
||||
////DebugUtil.Log(2, "Polyline has {0} vertiecs", polyLine.Count);
|
||||
//fPolylineGameObject go = GameObjectFactory.CreatePolylineGO(
|
||||
// "slice_outer", polyLine, slice_color, 0.1f, LineWidthType.World);
|
||||
//go.SetMaterial(slice_mat, true);
|
||||
//CC.ActiveScene.RootGameObject.AddChild(go, false);
|
||||
//SlicePolylines.Add(go);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
MatterHackers.gsSlicer/Slicer/PrintMeshSettings.cs
Normal file
74
MatterHackers.gsSlicer/Slicer/PrintMeshSettings.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
|
||||
namespace cotangent
|
||||
{
|
||||
public static class DebugUtil
|
||||
{
|
||||
internal static void Log(string v)
|
||||
{
|
||||
Console.WriteLine(v);
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal static void Log(int v1, string v2)
|
||||
{
|
||||
Console.WriteLine("{0} - {1}", v1, v2);
|
||||
}
|
||||
|
||||
internal static void Log(int v1, string v2, string msg, string trace)
|
||||
{
|
||||
Console.WriteLine("{0} - {1} {2}", v1, v2, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public class PrintMeshSettings
|
||||
{
|
||||
// WARNING: this class is serialized! Do not change enum constants!
|
||||
public int Version = 1;
|
||||
|
||||
public enum ObjectTypes
|
||||
{
|
||||
Solid = 0, Support = 1, Cavity = 2, CropRegion = 3, Ignored = 4
|
||||
}
|
||||
|
||||
public enum OpenMeshModes
|
||||
{
|
||||
Default = 0, Clipped = 1, Embedded = 2, Ignored = 3,
|
||||
}
|
||||
|
||||
public ObjectTypes ObjectType = ObjectTypes.Solid;
|
||||
public bool NoVoids = false;
|
||||
public bool OuterShellOnly = false;
|
||||
public OpenMeshModes OpenMeshMode = OpenMeshModes.Default;
|
||||
|
||||
public double Clearance = 0;
|
||||
public double OffsetXY = 0;
|
||||
|
||||
|
||||
public PrintMeshSettings Clone() {
|
||||
return new PrintMeshSettings() {
|
||||
ObjectType = this.ObjectType,
|
||||
NoVoids = this.NoVoids,
|
||||
OuterShellOnly = this.OuterShellOnly,
|
||||
OpenMeshMode = this.OpenMeshMode,
|
||||
Clearance = this.Clearance,
|
||||
OffsetXY = this.OffsetXY
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static gs.PrintMeshOptions.OpenPathsModes Convert(OpenMeshModes mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OpenMeshModes.Clipped: return gs.PrintMeshOptions.OpenPathsModes.Clipped;
|
||||
case OpenMeshModes.Embedded: return gs.PrintMeshOptions.OpenPathsModes.Embedded;
|
||||
case OpenMeshModes.Ignored: return gs.PrintMeshOptions.OpenPathsModes.Ignored;
|
||||
default:
|
||||
case OpenMeshModes.Default: return gs.PrintMeshOptions.OpenPathsModes.Default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
462
MatterHackers.gsSlicer/Slicer/PrintSettings.cs
Normal file
462
MatterHackers.gsSlicer/Slicer/PrintSettings.cs
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
|
||||
|
||||
using System;
|
||||
using gs;
|
||||
|
||||
namespace cotangent
|
||||
{
|
||||
public class PrintSettings
|
||||
{
|
||||
protected SingleMaterialFFFSettings Active;
|
||||
|
||||
protected bool bValueModified = false;
|
||||
public bool HasModifiedValues
|
||||
{
|
||||
get { return bValueModified; }
|
||||
}
|
||||
|
||||
|
||||
protected double layer_height = 0.2;
|
||||
public double LayerHeightMM
|
||||
{
|
||||
get { return layer_height; }
|
||||
set { if (layer_height != value) { layer_height = value; setting_modified(true, true); } }
|
||||
}
|
||||
public bool LayerHeightMM_Modified { get { return layer_height != Active.LayerHeightMM; } }
|
||||
|
||||
|
||||
public enum OpenMeshMode
|
||||
{
|
||||
Clipped = 0, Embedded = 1, Ignored = 2
|
||||
}
|
||||
OpenMeshMode open_mode = OpenMeshMode.Clipped;
|
||||
public OpenMeshMode OpenMode
|
||||
{
|
||||
get { return open_mode; }
|
||||
}
|
||||
public int OpenModeInt
|
||||
{
|
||||
get { return (int)open_mode; }
|
||||
set
|
||||
{
|
||||
OpenMeshMode newmode = (OpenMeshMode)value;
|
||||
if (open_mode != newmode)
|
||||
{
|
||||
open_mode = newmode; setting_modified(true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected int outer_shells = 2;
|
||||
public int OuterShells
|
||||
{
|
||||
get { return outer_shells; }
|
||||
set { if (outer_shells != value) { outer_shells = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool OuterShells_Modified { get { return outer_shells != Active.Shells; } }
|
||||
|
||||
|
||||
protected int roof_layers = 2;
|
||||
public int RoofLayers
|
||||
{
|
||||
get { return roof_layers; }
|
||||
set { if (roof_layers != value) { roof_layers = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool RoofLayers_Modified { get { return roof_layers != Active.RoofLayers; } }
|
||||
|
||||
|
||||
protected int floor_layers = 2;
|
||||
public int FloorLayers
|
||||
{
|
||||
get { return floor_layers; }
|
||||
set { if (floor_layers != value) { floor_layers = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool FloorLayers_Modified { get { return floor_layers != Active.FloorLayers; } }
|
||||
|
||||
|
||||
protected double infill_step = 3.0;
|
||||
public double InfillStepX
|
||||
{
|
||||
get { return infill_step; }
|
||||
set { if (infill_step != value) { infill_step = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool InfillStepX_Modified { get { return infill_step != Active.SparseLinearInfillStepX; } }
|
||||
|
||||
|
||||
protected int interior_solid_region_shells = 0;
|
||||
public int InteriorSolidRegionShells
|
||||
{
|
||||
get { return interior_solid_region_shells; }
|
||||
set { if (interior_solid_region_shells != value) { interior_solid_region_shells = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool InteriorSolidRegionShells_Modified { get { return interior_solid_region_shells != Active.InteriorSolidRegionShells; } }
|
||||
|
||||
|
||||
protected bool clip_self_overlaps = false;
|
||||
public bool ClipSelfOverlaps
|
||||
{
|
||||
get { return clip_self_overlaps; }
|
||||
set { if (clip_self_overlaps != value) { clip_self_overlaps = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool ClipSelfOverlaps_Modified { get { return clip_self_overlaps != Active.ClipSelfOverlaps; } }
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Start layer settings
|
||||
*/
|
||||
protected int start_layers = 0;
|
||||
public int StartLayers
|
||||
{
|
||||
get { return start_layers; }
|
||||
set { if (start_layers != value) { start_layers = value; setting_modified(true, true); } }
|
||||
}
|
||||
public bool StartLayers_Modified { get { return start_layers != Active.StartLayers; } }
|
||||
|
||||
|
||||
protected double start_layer_height = 0.2;
|
||||
public double StartLayerHeightMM
|
||||
{
|
||||
get { return start_layer_height; }
|
||||
set { if (start_layer_height != value) { start_layer_height = value; setting_modified(true, true); } }
|
||||
}
|
||||
public bool StartLayerHeightMM_Modified { get { return start_layer_height != Active.StartLayerHeightMM; } }
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Support settings
|
||||
*/
|
||||
|
||||
protected bool generate_support = false;
|
||||
public bool GenerateSupport
|
||||
{
|
||||
get { return generate_support; }
|
||||
set { if (generate_support != value) { generate_support = value; setting_modified(true, true); } }
|
||||
}
|
||||
public bool GenerateSupport_Modified { get { return generate_support != Active.GenerateSupport; } }
|
||||
|
||||
protected double overhang_angle = 35.0;
|
||||
public double OverhangAngleDeg
|
||||
{
|
||||
get { return overhang_angle; }
|
||||
set { if (overhang_angle != value) { overhang_angle = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool OverhangAngleDeg_Modified { get { return overhang_angle != Active.SupportOverhangAngleDeg; } }
|
||||
|
||||
protected bool support_minz_tips = true;
|
||||
public bool SupportMinZTips
|
||||
{
|
||||
get { return support_minz_tips; }
|
||||
set { if (support_minz_tips != value) { support_minz_tips = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool SupportMinZTips_Modified { get { return support_minz_tips != Active.SupportMinZTips; } }
|
||||
|
||||
protected double support_step = 3.0;
|
||||
public double SupportStepX
|
||||
{
|
||||
get { return support_step; }
|
||||
set { if (support_step != value) { support_step = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool SupportStepX_Modified { get { return support_step != Active.SupportSpacingStepX; } }
|
||||
|
||||
|
||||
protected bool enable_support_shell = false;
|
||||
public bool EnableSupportShell
|
||||
{
|
||||
get { return enable_support_shell; }
|
||||
set { if (enable_support_shell != value) { enable_support_shell = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool EnableSupportShell_Modified { get { return enable_support_shell != Active.EnableSupportShell; } }
|
||||
|
||||
|
||||
protected bool enable_support_release_opt = false;
|
||||
public bool EnableSupportReleaseOpt
|
||||
{
|
||||
get { return enable_support_release_opt; }
|
||||
set { if (enable_support_release_opt != value) { enable_support_release_opt = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool EnableSupportReleaseOpt_Modified { get { return enable_support_release_opt != Active.EnableSupportReleaseOpt; } }
|
||||
|
||||
|
||||
protected double support_solid_space = 0.3;
|
||||
public double SupportSolidSpace
|
||||
{
|
||||
get { return support_solid_space; }
|
||||
set { if (support_solid_space != value) { support_solid_space = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool SupportSolidSpace_Modified { get { return support_solid_space != Active.SupportSolidSpace; } }
|
||||
|
||||
|
||||
/*
|
||||
* Bridging settings
|
||||
*/
|
||||
|
||||
protected bool enable_bridging = false;
|
||||
public bool EnableBridging
|
||||
{
|
||||
get { return enable_bridging; }
|
||||
set { if (enable_bridging != value) { enable_bridging = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool EnableBridging_Modified { get { return enable_bridging != Active.EnableBridging; } }
|
||||
|
||||
protected double max_bridge_dist = 10.0;
|
||||
public double MaxBridgeDistanceMM
|
||||
{
|
||||
get { return max_bridge_dist; }
|
||||
set { if (max_bridge_dist != value) { max_bridge_dist = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool MaxBridgeDistanceMM_Modified { get { return max_bridge_dist != Active.MaxBridgeWidthMM; } }
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Extra settings
|
||||
*/
|
||||
|
||||
protected int layer_range_min = 1;
|
||||
public int LayerRangeMin
|
||||
{
|
||||
get { return layer_range_min; }
|
||||
set { if (layer_range_min != value) { layer_range_min = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool LayerRangeMin_Modified { get { return layer_range_min != (Active.LayerRangeFilter.a + 1); } }
|
||||
|
||||
|
||||
protected int layer_range_max = 999999999;
|
||||
public int LayerRangeMax
|
||||
{
|
||||
get { return layer_range_max; }
|
||||
set { if (layer_range_max != value) { layer_range_max = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool LayerRangeMax_Modified { get { return layer_range_max != (Active.LayerRangeFilter.b + 1); } }
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Machine settings
|
||||
*/
|
||||
|
||||
|
||||
protected double nozzle_diam = 0.4;
|
||||
public double NozzleDiameterMM
|
||||
{
|
||||
get { return nozzle_diam; }
|
||||
set { if (nozzle_diam != value) { nozzle_diam = value; setting_modified(true, true); } }
|
||||
}
|
||||
public bool NozzleDiameterMM_Modified { get { return nozzle_diam != Active.Machine.NozzleDiamMM; } }
|
||||
|
||||
protected double filament_diam = 0.4;
|
||||
public double FilamentDiameterMM
|
||||
{
|
||||
get { return filament_diam; }
|
||||
set { if (filament_diam != value) { filament_diam = value; setting_modified(true, true); } }
|
||||
}
|
||||
public bool FilamentDiameterMM_Modified { get { return filament_diam != Active.Machine.FilamentDiamMM; } }
|
||||
|
||||
|
||||
protected int extruder_temp = 230;
|
||||
public int ExtruderTempC
|
||||
{
|
||||
get { return extruder_temp; }
|
||||
set { if (extruder_temp != value) { extruder_temp = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool ExtruderTempC_Modified { get { return extruder_temp != Active.ExtruderTempC; } }
|
||||
|
||||
|
||||
public bool HasHeatedBed
|
||||
{
|
||||
get { return Active.Machine.HasHeatedBed; }
|
||||
}
|
||||
|
||||
protected int bed_temp = 0;
|
||||
public int BedTempC
|
||||
{
|
||||
get { return bed_temp; }
|
||||
set { if (bed_temp != value) { bed_temp = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool BedTempC_Modified { get { return bed_temp != Active.HeatedBedTempC; } }
|
||||
|
||||
|
||||
protected int print_speed = 90;
|
||||
public int PrintSpeedMMS
|
||||
{
|
||||
get { return print_speed; }
|
||||
set { if (print_speed != value) { print_speed = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool PrintSpeedMMS_Modified { get { return print_speed != (int)Math.Round(Active.RapidExtrudeSpeed / 60, 0); } }
|
||||
|
||||
|
||||
protected int travel_speed = 150;
|
||||
public int TravelSpeedMMS
|
||||
{
|
||||
get { return travel_speed; }
|
||||
set { if (travel_speed != value) { travel_speed = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool TravelSpeedMMS_Modified { get { return travel_speed != (int)Math.Round(Active.RapidTravelSpeed / 60, 0); } }
|
||||
|
||||
|
||||
protected int fan_speed_x = 100;
|
||||
public int FanSpeedX
|
||||
{
|
||||
get { return fan_speed_x; }
|
||||
set { if (fan_speed_x != value) { fan_speed_x = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool FanSpeedX_Modified { get { return fan_speed_x != (int)Math.Round(Active.FanSpeedX * 100, 0); } }
|
||||
|
||||
|
||||
protected int bed_size_x = 100;
|
||||
public int BedSizeXMM
|
||||
{
|
||||
get { return bed_size_x; }
|
||||
set { if (bed_size_x != value) { bed_size_x = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool BedSizeXMM_Modified { get { return bed_size_x != (int)Active.Machine.BedSizeXMM; } }
|
||||
|
||||
protected int bed_size_y = 100;
|
||||
public int BedSizeYMM
|
||||
{
|
||||
get { return bed_size_y; }
|
||||
set { if (bed_size_y != value) { bed_size_y = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool BedSizeYMM_Modified { get { return bed_size_y != (int)Active.Machine.BedSizeYMM; } }
|
||||
|
||||
protected int bed_size_z = 100;
|
||||
public int BedSizeZMM
|
||||
{
|
||||
get { return bed_size_z; }
|
||||
set { if (bed_size_z != value) { bed_size_z = value; setting_modified(false, true); } }
|
||||
}
|
||||
public bool BedSizeZMM_Modified { get { return bed_size_z != (int)Active.Machine.MaxHeightMM; } }
|
||||
|
||||
|
||||
public delegate void SettingsModifiedEvent(PrintSettings settings);
|
||||
public event SettingsModifiedEvent OnNewSettings;
|
||||
public event SettingsModifiedEvent OnSettingModified;
|
||||
|
||||
|
||||
void setting_modified(bool invalidate_slicing, bool invalidate_paths)
|
||||
{
|
||||
//if (invalidate_slicing)
|
||||
// CC.InvalidateSlicing();
|
||||
//else if (invalidate_paths)
|
||||
// CC.InvalidateToolPaths();
|
||||
bValueModified = true;
|
||||
OnSettingModified?.Invoke(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void UpdateFromSettings(PlanarAdditiveSettings settings)
|
||||
{
|
||||
if (settings == null)
|
||||
return;
|
||||
if (settings is SingleMaterialFFFSettings == false)
|
||||
throw new Exception("PrintSettings.UpdateFromSettings: invalid settings type!");
|
||||
|
||||
SingleMaterialFFFSettings ss = settings as SingleMaterialFFFSettings;
|
||||
Active = ss;
|
||||
|
||||
LayerHeightMM = ss.LayerHeightMM;
|
||||
OuterShells = ss.Shells;
|
||||
RoofLayers = ss.RoofLayers;
|
||||
FloorLayers = ss.FloorLayers;
|
||||
InfillStepX = ss.SparseLinearInfillStepX;
|
||||
ClipSelfOverlaps = ss.ClipSelfOverlaps;
|
||||
InteriorSolidRegionShells = ss.InteriorSolidRegionShells;
|
||||
StartLayers = ss.StartLayers;
|
||||
StartLayerHeightMM = ss.StartLayerHeightMM;
|
||||
|
||||
GenerateSupport = ss.GenerateSupport;
|
||||
OverhangAngleDeg = ss.SupportOverhangAngleDeg;
|
||||
SupportMinZTips = ss.SupportMinZTips;
|
||||
EnableSupportShell = ss.EnableSupportShell;
|
||||
EnableSupportReleaseOpt = ss.EnableSupportReleaseOpt;
|
||||
SupportStepX = ss.SupportSpacingStepX;
|
||||
SupportSolidSpace = ss.SupportSolidSpace;
|
||||
|
||||
EnableBridging = ss.EnableBridging;
|
||||
MaxBridgeDistanceMM = ss.MaxBridgeWidthMM;
|
||||
|
||||
LayerRangeMin = ss.LayerRangeFilter.a + 1;
|
||||
LayerRangeMax = ss.LayerRangeFilter.b + 1;
|
||||
|
||||
NozzleDiameterMM = ss.Machine.NozzleDiamMM;
|
||||
FilamentDiameterMM = ss.Machine.FilamentDiamMM;
|
||||
ExtruderTempC = ss.ExtruderTempC;
|
||||
BedTempC = ss.HeatedBedTempC;
|
||||
PrintSpeedMMS = (int)Math.Round(ss.RapidExtrudeSpeed / 60, 0);
|
||||
TravelSpeedMMS = (int)Math.Round(ss.RapidTravelSpeed / 60, 0);
|
||||
FanSpeedX = (int)Math.Round(ss.FanSpeedX * 100, 0);
|
||||
BedSizeXMM = (int)ss.Machine.BedSizeXMM;
|
||||
BedSizeYMM = (int)ss.Machine.BedSizeYMM;
|
||||
BedSizeZMM = (int)ss.Machine.MaxHeightMM;
|
||||
|
||||
bValueModified = false;
|
||||
OnNewSettings?.Invoke(this);
|
||||
}
|
||||
|
||||
public void WriteToSettings(PlanarAdditiveSettings settings)
|
||||
{
|
||||
if (settings is SingleMaterialFFFSettings == false)
|
||||
throw new Exception("PrintSettings.UpdateToSettings: invalid settings type!");
|
||||
WriteToSettings(settings as SingleMaterialFFFSettings);
|
||||
}
|
||||
public void WriteToSettings(SingleMaterialFFFSettings settings)
|
||||
{
|
||||
settings.LayerHeightMM = LayerHeightMM;
|
||||
settings.Shells = OuterShells;
|
||||
settings.RoofLayers = RoofLayers;
|
||||
settings.FloorLayers = FloorLayers;
|
||||
settings.SparseLinearInfillStepX = InfillStepX;
|
||||
settings.ClipSelfOverlaps = ClipSelfOverlaps;
|
||||
settings.InteriorSolidRegionShells = InteriorSolidRegionShells;
|
||||
settings.StartLayers = StartLayers;
|
||||
settings.StartLayerHeightMM = StartLayerHeightMM;
|
||||
|
||||
settings.GenerateSupport = GenerateSupport;
|
||||
settings.SupportOverhangAngleDeg = OverhangAngleDeg;
|
||||
settings.SupportMinZTips = SupportMinZTips;
|
||||
settings.EnableSupportShell = EnableSupportShell;
|
||||
settings.EnableSupportReleaseOpt = EnableSupportReleaseOpt;
|
||||
settings.SupportSpacingStepX = SupportStepX;
|
||||
settings.SupportSolidSpace = SupportSolidSpace;
|
||||
|
||||
settings.EnableBridging = EnableBridging;
|
||||
settings.MaxBridgeWidthMM = MaxBridgeDistanceMM;
|
||||
|
||||
int use_min = Math.Max(0, LayerRangeMin - 1);
|
||||
int use_max = (LayerRangeMax == 0) ? 999999999 : LayerRangeMax - 1;
|
||||
if (use_max < use_min)
|
||||
use_max = use_min;
|
||||
settings.LayerRangeFilter = new g3.Interval1i(use_min, use_max);
|
||||
|
||||
settings.FanSpeedX = (double)FanSpeedX / 100.0;
|
||||
|
||||
settings.Machine.NozzleDiamMM = NozzleDiameterMM;
|
||||
settings.Machine.FilamentDiamMM = FilamentDiameterMM;
|
||||
settings.ExtruderTempC = ExtruderTempC;
|
||||
settings.HeatedBedTempC = BedTempC;
|
||||
settings.RapidExtrudeSpeed = PrintSpeedMMS * 60;
|
||||
settings.RapidTravelSpeed = TravelSpeedMMS * 60;
|
||||
settings.Machine.BedSizeXMM = BedSizeXMM;
|
||||
settings.Machine.BedSizeYMM = BedSizeYMM;
|
||||
settings.Machine.MaxHeightMM = BedSizeZMM;
|
||||
}
|
||||
|
||||
|
||||
public SingleMaterialFFFSettings CloneCurrentSettings()
|
||||
{
|
||||
SingleMaterialFFFSettings clone = Active.CloneAs<SingleMaterialFFFSettings>();
|
||||
WriteToSettings(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
403
MatterHackers.gsSlicer/Slicer/SettingsSerializer.cs
Normal file
403
MatterHackers.gsSlicer/Slicer/SettingsSerializer.cs
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Globalization;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
||||
namespace gs
|
||||
{
|
||||
/// <summary>
|
||||
/// Store/restore additive settings data structures using JSON serialization
|
||||
/// </summary>
|
||||
public class SettingsSerializer
|
||||
{
|
||||
|
||||
public SettingsSerializer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read all .txt files in Path and try to parse each one as a Settings object
|
||||
/// </summary>
|
||||
public bool RestoreFromFolder(string sPath, out List<PlanarAdditiveSettings> SettingsList, out List<string> SourceFilePaths)
|
||||
{
|
||||
SettingsList = new List<PlanarAdditiveSettings>();
|
||||
SourceFilePaths = new List<string>();
|
||||
|
||||
string[] files = Directory.GetFiles(sPath);
|
||||
foreach (string filePath in files)
|
||||
{
|
||||
if (!filePath.EndsWith(".txt"))
|
||||
continue;
|
||||
|
||||
var save_culture = Thread.CurrentThread.CurrentCulture;
|
||||
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
string data = File.ReadAllText(filePath);
|
||||
Thread.CurrentThread.CurrentCulture = save_culture;
|
||||
|
||||
SingleMaterialFFFSettings settings = JsonToSettings(data);
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
//DebugUtil.Log("SettingsSerializer.RestoreFromFolder: error reading " + filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingsList.Add(settings);
|
||||
SourceFilePaths.Add(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
return SettingsList.Count > 0;
|
||||
}
|
||||
|
||||
|
||||
static Assembly GSGCODE_ASM = null;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Parse the json in data string into the right type of Settings object
|
||||
/// </summary>
|
||||
public SingleMaterialFFFSettings JsonToSettings(string data)
|
||||
{
|
||||
if (!is_settings_json(data))
|
||||
return null;
|
||||
|
||||
// [RMS] because we split gsGCode into a separate dll, Type.GetType() will not find it.
|
||||
// We have to use a handle to the relevant assembly.
|
||||
if (GSGCODE_ASM == null)
|
||||
GSGCODE_ASM = Assembly.Load("gsGCode");
|
||||
|
||||
int typeIdx = data.IndexOf("\"ClassTypeName\"");
|
||||
SingleMaterialFFFSettings settings = null;
|
||||
if (typeIdx > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
int commaIdx = typeIdx + 1;
|
||||
while (data[commaIdx] != ',')
|
||||
commaIdx++;
|
||||
int startIdx = typeIdx + 18;
|
||||
string className = data.Substring(startIdx, commaIdx - startIdx - 1);
|
||||
//var type = Type.GetType(className);
|
||||
var type = GSGCODE_ASM.GetType(className);
|
||||
object o = JsonConvert.DeserializeObject(data, type);
|
||||
settings = o as SingleMaterialFFFSettings;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore disasters
|
||||
}
|
||||
}
|
||||
|
||||
// either no typename, or we failed to construct it
|
||||
if (settings == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
settings = JsonConvert.DeserializeObject<SingleMaterialFFFSettings>(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool is_settings_json(string s)
|
||||
{
|
||||
return s.Contains("ManufacturerUUID") && s.Contains("ModelUUID");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//public void RefreshSettingsFromDisk(MachineDatabase db, MachinePreset preset)
|
||||
//{
|
||||
// if (File.Exists(preset.SourcePath) == false)
|
||||
// throw new Exception("SettingsSerializer.RefreshSettingsFromDisk: path " + preset.SourcePath + " does not exist!");
|
||||
|
||||
// var save_culture = Thread.CurrentThread.CurrentCulture;
|
||||
// Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
// string data = File.ReadAllText(preset.SourcePath);
|
||||
// Thread.CurrentThread.CurrentCulture = save_culture;
|
||||
|
||||
// SingleMaterialFFFSettings settings = JsonToSettings(data);
|
||||
// if ( settings == null )
|
||||
// throw new Exception("SettingsSerializer.RefreshSettingsFromDisk: json data could not be parsed!");
|
||||
|
||||
// preset.Settings = settings;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//public void StoreSettings(MachineDatabase db, MachinePreset preset, bool bCreate = false)
|
||||
//{
|
||||
// JsonSerializerSettings jsonSettings = makeWriteSerializer();
|
||||
// if (bCreate == false && File.Exists(preset.SourcePath) == false)
|
||||
// throw new Exception("SettingsSerializer.StoreSettings: path " + preset.SourcePath + " does not exist!");
|
||||
|
||||
// var save_culture = Thread.CurrentThread.CurrentCulture;
|
||||
// Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
|
||||
// string json = JsonConvert.SerializeObject(preset.Settings, jsonSettings);
|
||||
// System.IO.File.WriteAllText(preset.SourcePath, json);
|
||||
|
||||
// Thread.CurrentThread.CurrentCulture = save_culture;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//public void UpdateSettingsFromJson(MachineDatabase db, MachinePreset preset, string newJson, bool bCreate)
|
||||
//{
|
||||
// JsonSerializerSettings jsonSettings = makeWriteSerializer();
|
||||
// if (bCreate == false && File.Exists(preset.SourcePath) == false)
|
||||
// throw new Exception("SettingsSerializer.StoreSettings: path " + preset.SourcePath + " does not exist!");
|
||||
|
||||
// var save_culture = Thread.CurrentThread.CurrentCulture;
|
||||
// Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
// System.IO.File.WriteAllText(preset.SourcePath, newJson);
|
||||
// Thread.CurrentThread.CurrentCulture = save_culture;
|
||||
|
||||
// RefreshSettingsFromDisk(db, preset);
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
public bool ValidateSettingsJson(string json)
|
||||
{
|
||||
// [RMS] this just checks if string is valid json...
|
||||
if (!is_valid_json(json))
|
||||
return false;
|
||||
|
||||
var settings = JsonToSettings(json);
|
||||
if (settings == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// check if input string is valid json
|
||||
/// details: https://stackoverflow.com/questions/14977848/how-to-make-sure-that-string-is-valid-json-using-json-net
|
||||
/// </summary>
|
||||
protected bool is_valid_json(string json)
|
||||
{
|
||||
string strInput = json.Trim();
|
||||
if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
|
||||
(strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = JToken.Parse(strInput);
|
||||
return true;
|
||||
}
|
||||
catch (JsonReaderException jex)
|
||||
{
|
||||
//Exception in parsing json
|
||||
Console.WriteLine(jex.Message);
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex) //some other exception
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//public void GenerateSettingsFolder(MachineDatabase db, string rootPath)
|
||||
//{
|
||||
// JsonSerializerSettings jsonSettings = makeWriteSerializer();
|
||||
|
||||
// foreach ( Manufacturer mfg in db.Manufacturers ) {
|
||||
// string mfgPath = Path.Combine(rootPath, mfg.Name);
|
||||
// if (!Directory.Exists(mfgPath)) {
|
||||
// Directory.CreateDirectory(mfgPath);
|
||||
// if (!Directory.Exists(mfgPath))
|
||||
// throw new Exception("SettingsSerializer: cannot create directory for manufacturer " + mfg.Name);
|
||||
// }
|
||||
|
||||
// IReadOnlyList<MachineModel> machines = db.ModelsForManufacturer(mfg);
|
||||
// foreach ( MachineModel machine in machines) {
|
||||
// string machinePath = Path.Combine(mfgPath, machine.Name);
|
||||
// if (! Directory.Exists(machinePath) ) {
|
||||
// Directory.CreateDirectory(machinePath);
|
||||
// if (!Directory.Exists(machinePath))
|
||||
// throw new Exception("SettingsSerializer: cannot create directory for machine " + mfg.Name + "::" + machine.Name);
|
||||
// }
|
||||
|
||||
|
||||
// PlanarAdditiveSettings settings = machine.DefaultPreset.Settings;
|
||||
// string settingsPath = Path.Combine(machinePath, settings.Identifier + ".txt");
|
||||
|
||||
// var save_culture = Thread.CurrentThread.CurrentCulture;
|
||||
// Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
// string json = JsonConvert.SerializeObject(settings, jsonSettings);
|
||||
// System.IO.File.WriteAllText(settingsPath, json);
|
||||
// Thread.CurrentThread.CurrentCulture = save_culture;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//public string CreateNewSettingsFolder(MachineDatabase db, Manufacturer mfg, MachineModel machine, string rootPath)
|
||||
//{
|
||||
// string mfgPath = Path.Combine(rootPath, mfg.Name);
|
||||
// if (!Directory.Exists(mfgPath)) {
|
||||
// Directory.CreateDirectory(mfgPath);
|
||||
// if (!Directory.Exists(mfgPath))
|
||||
// throw new Exception("SettingsSerializer: cannot create directory for manufacturer " + mfg.Name);
|
||||
// }
|
||||
|
||||
// string machinePath = Path.Combine(mfgPath, machine.Name);
|
||||
// if (!Directory.Exists(machinePath)) {
|
||||
// Directory.CreateDirectory(machinePath);
|
||||
// if (!Directory.Exists(machinePath))
|
||||
// throw new Exception("SettingsSerializer: cannot create directory for machine " + mfg.Name + "::" + machine.Name);
|
||||
// }
|
||||
|
||||
// return machinePath;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
JsonSerializerSettings makeWriteSerializer()
|
||||
{
|
||||
JsonSerializerSettings jsonSettings = new JsonSerializerSettings();
|
||||
jsonSettings.Converters.Add(
|
||||
new Newtonsoft.Json.Converters.StringEnumConverter());
|
||||
jsonSettings.Formatting = Formatting.Indented;
|
||||
jsonSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||
jsonSettings.ContractResolver = SettingsContractResolver.MyInstance;
|
||||
return jsonSettings;
|
||||
}
|
||||
|
||||
|
||||
JsonSerializerSettings makeReadSerializer()
|
||||
{
|
||||
JsonSerializerSettings jsonSettings = new JsonSerializerSettings();
|
||||
jsonSettings.Converters.Add(
|
||||
new Newtonsoft.Json.Converters.StringEnumConverter());
|
||||
jsonSettings.Formatting = Formatting.Indented;
|
||||
jsonSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||
return jsonSettings;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// JSON.Net settings contract - this lets you sort and filter the fields that get serialized
|
||||
/// </summary>
|
||||
public class SettingsContractResolver : DefaultContractResolver
|
||||
{
|
||||
public static readonly SettingsContractResolver MyInstance = new SettingsContractResolver();
|
||||
|
||||
public HashSet<string> IgnoreFields = new HashSet<string>();
|
||||
|
||||
public SettingsContractResolver()
|
||||
{
|
||||
IgnoreFields.Add("LayerRangeFilter");
|
||||
IgnoreFields.Add("BaseMachine");
|
||||
}
|
||||
|
||||
// use this to filter out fields
|
||||
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
||||
{
|
||||
JsonProperty property = base.CreateProperty(member, memberSerialization);
|
||||
if (property.DeclaringType == typeof(SingleMaterialFFFSettings) && IgnoreFields.Contains(property.PropertyName))
|
||||
{
|
||||
property.Ignored = true;
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
// sort property names alphabetically
|
||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||
{
|
||||
List<JsonProperty> sorted =
|
||||
base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList();
|
||||
|
||||
if (type == typeof(FFFMachineInfo))
|
||||
sorted = SortMachine(sorted);
|
||||
|
||||
// [TODO] construct an ordering here?
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
|
||||
static readonly string[] machine_order = new string[] {
|
||||
"ManufacturerName",
|
||||
"ManufacturerUUID",
|
||||
"ModelIdentifier",
|
||||
"ModelUUID",
|
||||
"Class",
|
||||
"BedSizeXMM",
|
||||
"BedSizeYMM",
|
||||
"MaxHeightMM",
|
||||
"FilamentDiamMM",
|
||||
"NozzleDiamMM",
|
||||
"MinExtruderTempC",
|
||||
"MaxExtruderTempC",
|
||||
"HasHeatedBed",
|
||||
"MinBedTempC",
|
||||
"MaxBedTempC",
|
||||
"MinLayerHeightMM",
|
||||
"MaxLayerHeightMM"
|
||||
};
|
||||
|
||||
List<JsonProperty> SortMachine(List<JsonProperty> input)
|
||||
{
|
||||
List<JsonProperty> sorted = new List<JsonProperty>(input.Count);
|
||||
bool[] used = new bool[input.Count];
|
||||
for (int i = 0; i < machine_order.Length; ++i)
|
||||
{
|
||||
int idx = input.FindIndex((v) => { return v.PropertyName.Equals(machine_order[i]); });
|
||||
if (idx >= 0)
|
||||
{
|
||||
sorted.Add(input[idx]);
|
||||
}
|
||||
used[idx] = true;
|
||||
}
|
||||
for (int i = 0; i < input.Count; ++i)
|
||||
{
|
||||
if (used[i] == false)
|
||||
sorted.Add(input[i]);
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
179
MatterHackers.gsSlicer/Slicer/ToolpathGenerator.cs
Normal file
179
MatterHackers.gsSlicer/Slicer/ToolpathGenerator.cs
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using g3;
|
||||
using gs;
|
||||
|
||||
namespace cotangent
|
||||
{
|
||||
public class ToolpathGenerator
|
||||
{
|
||||
private object active_compute_lock = new object();
|
||||
|
||||
public GCodeFile CurrentGCode;
|
||||
public ToolpathSet Toolpaths;
|
||||
public LayersDetector LayerInfo;
|
||||
public SingleMaterialFFFSettings Settings;
|
||||
|
||||
public PlanarSliceStack Slices;
|
||||
|
||||
public bool ToolpathsValid;
|
||||
public bool ToolpathsFailed;
|
||||
|
||||
public bool ShowActualGCodePaths = false;
|
||||
|
||||
public bool PauseToolpathing = false;
|
||||
|
||||
public ToolpathGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
public void CreateToolPaths(PrintMeshAssembly meshes, PlanarSliceStack slices, PrintSettings settings)
|
||||
{
|
||||
// have to wait for valid slice stack
|
||||
if (slices == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//mark_spawn_time();
|
||||
this.BuildToolPaths(new GenerationTask
|
||||
{
|
||||
PrintSettings = settings.CloneCurrentSettings(),
|
||||
Meshes = meshes,
|
||||
SliceSet = slices,
|
||||
InterpretGCodePaths = ShowActualGCodePaths
|
||||
}, settings);
|
||||
}
|
||||
|
||||
private void BuildToolPaths(GenerationTask generationTask, PrintSettings settings)
|
||||
{
|
||||
lock (active_compute_lock)
|
||||
{
|
||||
DebugUtil.Log("[ToolpathGenerator] Spawning Compute!!");
|
||||
generationTask.Compute(settings);
|
||||
|
||||
if (generationTask.Success)
|
||||
{
|
||||
CurrentGCode = generationTask.gcode;
|
||||
Toolpaths = generationTask.paths;
|
||||
LayerInfo = generationTask.layerInfo;
|
||||
Settings = generationTask.PrintSettings;
|
||||
Slices = generationTask.SliceSet;
|
||||
ToolpathsValid = true;
|
||||
ToolpathsFailed = false;
|
||||
|
||||
//CC.Objects.SetToolpaths(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentGCode = null;
|
||||
Toolpaths = null;
|
||||
LayerInfo = null;
|
||||
Settings = null;
|
||||
Slices = null;
|
||||
ToolpathsValid = false;
|
||||
ToolpathsFailed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GenerationTask
|
||||
{
|
||||
// input data
|
||||
public SingleMaterialFFFSettings PrintSettings;
|
||||
public PrintMeshAssembly Meshes;
|
||||
public PlanarSliceStack SliceSet;
|
||||
public bool InterpretGCodePaths;
|
||||
|
||||
// computed data
|
||||
public bool Finished;
|
||||
public bool Success;
|
||||
public bool RequestCancel;
|
||||
public GCodeFile gcode;
|
||||
public ToolpathSet paths;
|
||||
public LayersDetector layerInfo;
|
||||
|
||||
// internal
|
||||
SingleMaterialFFFPrintGenerator printer;
|
||||
|
||||
public GenerationTask()
|
||||
{
|
||||
Finished = false;
|
||||
Success = false;
|
||||
RequestCancel = false;
|
||||
}
|
||||
|
||||
public void Compute(PrintSettings settings)
|
||||
{
|
||||
RequestCancel = false;
|
||||
|
||||
printer =
|
||||
new SingleMaterialFFFPrintGenerator(Meshes, SliceSet, PrintSettings);
|
||||
|
||||
if (PrintSettings.EnableSupportReleaseOpt)
|
||||
{
|
||||
printer.LayerPostProcessor = new SupportConnectionPostProcessor()
|
||||
{
|
||||
ZOffsetMM = PrintSettings.SupportReleaseGap
|
||||
};
|
||||
}
|
||||
|
||||
// if we aren't interpreting GCode, we want generator to return its path set
|
||||
printer.AccumulatePathSet = (InterpretGCodePaths == false);
|
||||
|
||||
// set clip region
|
||||
Box2d clip_box = new Box2d(Vector2d.Zero,
|
||||
new Vector2d(settings.BedSizeXMM / 2, settings.BedSizeYMM / 2));
|
||||
printer.PathClipRegions = new List<GeneralPolygon2d>() {
|
||||
new GeneralPolygon2d(new Polygon2d(clip_box.ComputeVertices()))
|
||||
};
|
||||
|
||||
printer.ErrorF = (msg, trace) =>
|
||||
{
|
||||
if (RequestCancel == false)
|
||||
DebugUtil.Log(2, "Slicer Error! msg: {0} stack {1}", msg, trace);
|
||||
};
|
||||
|
||||
DebugUtil.Log(2, "Generating gcode...");
|
||||
|
||||
try
|
||||
{
|
||||
if (printer.Generate() == false)
|
||||
throw new Exception("generate failed"); // this will be caught below
|
||||
|
||||
gcode = printer.Result;
|
||||
|
||||
//DebugUtil.Log(2, "Interpreting gcode...");
|
||||
|
||||
if (InterpretGCodePaths)
|
||||
{
|
||||
GCodeToToolpaths converter = new GCodeToToolpaths();
|
||||
MakerbotInterpreter interpreter = new MakerbotInterpreter();
|
||||
interpreter.AddListener(converter);
|
||||
InterpretArgs interpArgs = new InterpretArgs();
|
||||
interpreter.Interpret(gcode, interpArgs);
|
||||
paths = converter.PathSet;
|
||||
}
|
||||
else
|
||||
paths = printer.AccumulatedPaths;
|
||||
|
||||
//DebugUtil.Log(2, "Detecting layers...");
|
||||
layerInfo = new LayersDetector(paths);
|
||||
|
||||
Success = true;
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugUtil.Log("ToolpathGenerator.Compute: exception: " + e.Message);
|
||||
Success = false;
|
||||
}
|
||||
|
||||
Finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
MatterHackers.gsSlicer/gsSlicerPlugin.cs
Normal file
51
MatterHackers.gsSlicer/gsSlicerPlugin.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright (c) 2019, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using MatterHackers.MatterControl.Extensibility;
|
||||
using MatterHackers.MatterControl.SlicerConfiguration;
|
||||
|
||||
namespace MatterHackers.gsBundle
|
||||
{
|
||||
public class gsSlicerPlugin : IApplicationPlugin
|
||||
{
|
||||
public void Initialize()
|
||||
{
|
||||
PrinterSettings.Slicer = new BasicSlicer();
|
||||
}
|
||||
|
||||
public PluginInfo MetaData => new PluginInfo()
|
||||
{
|
||||
About = "gsSlicer for MatterControl",
|
||||
Developer = "MatterHackers Inc.",
|
||||
Name = "MH-gsSlicer",
|
||||
Url = "https://www.matterhackers.com/MatterControl",
|
||||
UUID = "0384EBD9-072F-4295-AE48-270FC256B48B"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 29ad0540f5742e1a196174cdaf430410921b2cfc
|
||||
Subproject commit 98150c5a700d51594df7de70e576a21a12912a94
|
||||
1
Submodules/geometry3Sharp
Submodule
1
Submodules/geometry3Sharp
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 595abad18cb7818eea14bad060b3e958118af44e
|
||||
1
Submodules/gsGCode
Submodule
1
Submodules/gsGCode
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 0d9c4761e7e0ad35c7feb5094635c3b81aedff82
|
||||
1
Submodules/gsSlicer
Submodule
1
Submodules/gsSlicer
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 4ca5200c3346a3df572deb2b189f22060a8348f6
|
||||
Loading…
Add table
Add a link
Reference in a new issue