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
|
url = https://github.com/MatterHackers/MatterSlice.git
|
||||||
[submodule "Submodules/agg-sharp"]
|
[submodule "Submodules/agg-sharp"]
|
||||||
path = 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