mattercontrol/MatterHackers.gsSlicer/Slicer/GeometrySlicer.cs
2020-02-07 15:26:30 -08:00

292 lines
8 KiB
C#

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);
}
}
}
}
}