using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using Tango.BL.Entities;
using Tango.BL.Enumerations;
using Tango.ColorConversion;
using Tango.Core;
using Tango.Core.ExtensionMethods;
using Tango.PMR.ColorLab;
namespace Tango.Integration.Operation
{
///
/// Represents the default gradient steps generation configuration.
///
public class DefaultGradientGenerationConfiguration : ExtendedObject, IGradientGenerationConfiguration
{
private class CMYK
{
public double C { get; set; }
public double M { get; set; }
public double Y { get; set; }
public double K { get; set; }
public double OffsetPercent { get; set; }
}
private class LiquidVolumesStop
{
public Dictionary Volumes { get; set; }
public double OffsetPercent { get; set; }
public LiquidVolumesStop()
{
Volumes = new Dictionary();
}
}
private bool aborted;
private bool _isEnabled;
///
/// Gets or sets a value indicating whether to generate the gradient steps.
///
public bool IsEnabled
{
get { return _isEnabled; }
set { _isEnabled = value; RaisePropertyChangedAuto(); }
}
private int _resolutionCM;
///
/// Gets or sets the gradient steps resolution in centimeters.
///
public int ResolutionCM
{
get { return _resolutionCM; }
set { _resolutionCM = value; RaisePropertyChangedAuto(); }
}
///
/// Initializes a new instance of the class.
///
public DefaultGradientGenerationConfiguration()
{
ResolutionCM = 500;
}
#region Standard Method
///
/// Creates a collection of brush stops representing the required gradient steps.
///
/// The segment.
/// The job
/// The process parameters.
/// Progress callback.
///
public List Generate(Segment segment, Job job, ProcessParametersTable processParameters, Action progress = null)
{
if (processParameters.ProcessParametersTablesGroup.Rml.UseColorLibGradients)
{
return GenerateUsingColorLib(segment, job, processParameters, progress);
}
aborted = false;
List stops = new List();
var previousSegmentsLength = segment.GetPreviousSegments().Sum(x => x.Length);
int stopIndex = 1;
if (ResolutionCM > segment.Length * 100d)
{
return segment.BrushStops.ToList();
}
IColorConverter converter = new DefaultColorConverter();
var clonedStops = segment.BrushStops.ToList().Select(x => x.Clone(segment)).OrderBy(x => x.StopIndex).ToList();
foreach (var stop in clonedStops)
{
if (aborted) return stops;
if (stop.LiquidVolumes == null)
{
stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters);
}
if ((stop.BrushColorSpace == ColorSpaces.RGB || stop.BrushColorSpace == ColorSpaces.LAB) && !stop.IsTransparent && !stop.IsWhite)
{
var output = converter.Convert(stop, false);
output.ApplyOnBrushStop(stop, processParameters);
}
if ((stop.BrushColorSpace == ColorSpaces.Volume || stop.BrushColorSpace == ColorSpaces.Catalog) && job.Version >= 2 && clonedStops.Count == 5)
{
var firstStop = clonedStops.FirstOrDefault(x => x.StopIndex == 1);
var lastStop = clonedStops.FirstOrDefault(x => x.StopIndex == 5);
LiquidVolumesStop cmykfirst = GetCMYK(firstStop);
cmykfirst.OffsetPercent /= 100d;
LiquidVolumesStop cmyklast = GetCMYK(lastStop);
cmyklast.OffsetPercent /= 100d;
//set middle offset color
var middleOffsetStop = clonedStops.FirstOrDefault(x => x.StopIndex == 3);
if (middleOffsetStop != null)
{
LiquidVolumesStop cmykmiddle = GetRelativeCMYK(cmykfirst, cmyklast, middleOffsetStop.OffsetPercent / 100d);
foreach (var v in cmykmiddle.Volumes)
{
middleOffsetStop.SetLiquidVolume(v.Key, v.Value);
}
}
var firstOffsetStop = clonedStops.FirstOrDefault(x => x.StopIndex == 2);
if (firstOffsetStop != null)
{
foreach (var v in cmykfirst.Volumes)
{
firstOffsetStop.SetLiquidVolume(v.Key, v.Value);
}
}
var secondOffsetStop = clonedStops.FirstOrDefault(x => x.StopIndex == 4);
if (secondOffsetStop != null)
{
foreach (var v in cmyklast.Volumes)
{
secondOffsetStop.SetLiquidVolume(v.Key, v.Value);
}
}
}
}
var refStop = clonedStops.First().Clone(segment);
decimal segment_length = (decimal)segment.Length;
for (decimal cm = 0; cm <= segment_length; cm += (ResolutionCM / 100M))
{
if (aborted) return stops;
double offset = (double)cm / segment.Length;
var cmyk = GetRelativeCMYK(clonedStops.ToList(), offset);
var stop = refStop.Clone(segment);
stop.OffsetPercent = offset * 100d;
stop.OffsetMeters = segment.Length * offset;
stop.StopIndex = stopIndex++;
foreach (var v in cmyk.Volumes)
{
stop.SetVolume(v.Key, v.Value);
}
stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters);
stops.Add(stop);
progress?.Invoke(new PreparingJobProgressEventArgs()
{
Job = job,
Total = job.Segments.Sum(x => x.Length),
Progress = previousSegmentsLength + (double)cm,
});
}
stops.Last().OffsetPercent = 100;
stops.Last().OffsetMeters = segment.Length;
progress?.Invoke(new PreparingJobProgressEventArgs()
{
Job = job,
Total = job.Segments.Sum(x => x.Length),
Progress = previousSegmentsLength + segment.Length,
});
return stops;
}
private LiquidVolumesStop GetRelativeCMYK(LiquidVolumesStop first, LiquidVolumesStop last, double offset)
{
LiquidVolumesStop cmyk = new LiquidVolumesStop();
foreach (var v in first.Volumes)
{
cmyk.Volumes[v.Key] = (float)((offset - first.OffsetPercent) * (last.Volumes[v.Key] - first.Volumes[v.Key]) / (last.OffsetPercent - first.OffsetPercent) + first.Volumes[v.Key]);
}
//cmyk.OffsetPercent = offset;
return cmyk;
}
private LiquidVolumesStop GetRelativeCMYK(List brushStopsCollection, double offset)
{
BrushStop refStop = brushStopsCollection.First();
var cmykCollection = brushStopsCollection.Select(x => GetCMYK(x)).ToList();
cmykCollection.ForEach(x => x.OffsetPercent = x.OffsetPercent / 100d);
var stop = cmykCollection.FirstOrDefault(f => f.OffsetPercent == offset);
if (stop != null) return stop;
LiquidVolumesStop before = cmykCollection.Where(w => w.OffsetPercent == cmykCollection.Min(m => m.OffsetPercent)).First();
LiquidVolumesStop after = cmykCollection.Where(w => w.OffsetPercent == cmykCollection.Max(m => m.OffsetPercent)).Last();
foreach (var gs in cmykCollection)
{
if (gs.OffsetPercent < offset && gs.OffsetPercent > before.OffsetPercent)
{
before = gs;
}
if (gs.OffsetPercent > offset && gs.OffsetPercent < after.OffsetPercent)
{
after = gs;
}
}
LiquidVolumesStop cmyk = new LiquidVolumesStop();
foreach (var v in refStop.LiquidVolumesOrderedPigmentedForStandardUser.ToList())
{
cmyk.Volumes[v.LiquidType] = (float)((offset - before.OffsetPercent) * (after.Volumes[v.LiquidType] - before.Volumes[v.LiquidType]) / (after.OffsetPercent - before.OffsetPercent) + before.Volumes[v.LiquidType]);
}
return cmyk;
}
private LiquidVolumesStop GetCMYK(BrushStop stop)
{
LiquidVolumesStop s = new LiquidVolumesStop();
foreach (var v in stop.LiquidVolumesOrderedPigmentedForStandardUser.ToList())
{
s.Volumes[v.LiquidType] = v.Volume;
}
s.OffsetPercent = stop.OffsetPercent;
return s;
}
private Color GetRelativeRGB(List brushStopsCollection, double offset)
{
brushStopsCollection = brushStopsCollection.Select(x => x.ShallowClone()).ToList();
brushStopsCollection.ForEach(x => x.OffsetPercent = x.OffsetPercent / 100d);
var point = brushStopsCollection.SingleOrDefault(f => f.OffsetPercent == offset);
if (point != null) return point.Color;
BrushStop before = brushStopsCollection.Where(w => w.OffsetPercent == brushStopsCollection.Min(m => m.OffsetPercent)).First();
BrushStop after = brushStopsCollection.Where(w => w.OffsetPercent == brushStopsCollection.Max(m => m.OffsetPercent)).Last();
foreach (var gs in brushStopsCollection)
{
if (gs.OffsetPercent < offset && gs.OffsetPercent > before.OffsetPercent)
{
before = gs;
}
if (gs.OffsetPercent > offset && gs.OffsetPercent < after.OffsetPercent)
{
after = gs;
}
}
var color = new Color();
color.ScA = (float)((offset - before.OffsetPercent) * (after.Color.ScA - before.Color.ScA) / (after.OffsetPercent - before.OffsetPercent) + before.Color.ScA);
color.ScR = (float)((offset - before.OffsetPercent) * (after.Color.ScR - before.Color.ScR) / (after.OffsetPercent - before.OffsetPercent) + before.Color.ScR);
color.ScG = (float)((offset - before.OffsetPercent) * (after.Color.ScG - before.Color.ScG) / (after.OffsetPercent - before.OffsetPercent) + before.Color.ScG);
color.ScB = (float)((offset - before.OffsetPercent) * (after.Color.ScB - before.Color.ScB) / (after.OffsetPercent - before.OffsetPercent) + before.Color.ScB);
return color;
}
#endregion
#region ColorLib Method
public List GenerateUsingColorLib(Segment segment, Job job, ProcessParametersTable processParameters, Action progress = null)
{
aborted = false;
List stops = segment.BrushStops.Select(x => x.Clone()).ToList();
var refStop = segment.BrushStops.First().Clone(segment);
IColorConverter converter = new DefaultColorConverter();
foreach (var stop in stops)
{
if (aborted) return stops;
if (stop.LiquidVolumes == null)
{
stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters);
}
}
var conversionOutput = converter.GenerateGradient(stops, segment.Length, job.Rml, job.Machine.Configuration);
List newStops = new List();
int stopIndex = 1;
foreach (var stop in conversionOutput.Stops)
{
var newStop = refStop.Clone(segment);
newStop.OffsetPercent = stop.Offset * 100d;
newStop.OffsetMeters = segment.Length * stop.Offset;
newStop.StopIndex = stopIndex++;
newStop.SetVolume(LiquidTypes.Cyan, GetStopVolume(stop, PMR.ColorLab.LiquidType.Cyan));
newStop.SetVolume(LiquidTypes.Magenta, GetStopVolume(stop, PMR.ColorLab.LiquidType.Magenta));
newStop.SetVolume(LiquidTypes.Yellow, GetStopVolume(stop, PMR.ColorLab.LiquidType.Yellow));
newStop.SetVolume(LiquidTypes.Black, GetStopVolume(stop, PMR.ColorLab.LiquidType.Black));
newStop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters);
newStops.Add(newStop);
}
progress?.Invoke(new PreparingJobProgressEventArgs()
{
Job = job,
Total = 100,
Progress = 100,
});
return newStops;
}
private double GetStopVolume(GradientOutputStop stop, PMR.ColorLab.LiquidType liquidType)
{
var liquid = stop.OutputLiquids.SingleOrDefault(x => x.LiquidType == liquidType);
return liquid != null ? liquid.Volume : 0;
}
#endregion
///
/// Aborts the current generation.
///
public void AbortCurrentGeneration()
{
aborted = true;
}
}
}