diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-08-03 12:36:24 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-08-03 12:36:24 +0300 |
| commit | f2a27972ca652ef568e5eede22d86f9698a08cca (patch) | |
| tree | 6c55d21cba6bfa8587d95fd27e17a5ec423b3b0d /Software/Visual_Studio | |
| parent | bd1221e36ee3e493dc25bd32559f846519fe60d0 (diff) | |
| parent | 05fc7b1f37ecc809acf65422a799a4d761b78acb (diff) | |
| download | Tango-f2a27972ca652ef568e5eede22d86f9698a08cca.tar.gz Tango-f2a27972ca652ef568e5eede22d86f9698a08cca.zip | |
Merge branch 'master' of https://twinetfs.visualstudio.com/Tango/_git/Tango
Diffstat (limited to 'Software/Visual_Studio')
21 files changed, 1515 insertions, 352 deletions
diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp index 8f4b55db9..930980726 100644 --- a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp +++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.cpp @@ -1,4 +1,5 @@ #include "ColorConverter.h" +#include "ColorConvert.h" #include "CalibrationPoint.pb-c.h" #include "CalibrationData.pb-c.h" #include "ColorSpace.pb-c.h" @@ -53,22 +54,23 @@ #define dETol 2.0 # define ROUNDINGDigits 2.0 #define maxPerRegion 100.0 -#define LowVolumeThreshold 2.0 +#define LowVolumeThreshold 0.0 #define LowVolHalf LowVolumeThreshold/2 +#define GradientEndThr 0.95 Tango::ColorLib::ColorConverter::ColorConverter() : m_A2BTransform(NULL), m_B2ATransform(NULL), m_GBD(NULL), m_CalibCurves(NULL), m_Conv02(NULL), m_GamutRegionMaxLim(NULL), m_maxNlPerCM(NULL), m_nA2BnSepIn(0), m_nA2BnSepOut(0), m_nB2AnSepIn(0), m_nB2AnSepOut(0), -m_nInks(0), m_nVolumes(0), m_AdaptWP(false), m_nGamutRegions(0), m_LinCurves(NULL), -m_nProcessRanges(0), m_ProcessRangesMaxP(NULL) +m_nInks(0), m_nVolumes(0), m_nGamutRegions(0), m_LinCurves(NULL), +m_nProcessRanges(0), m_ProcessRangesMaxP(NULL), m_GradStops(NULL), m_nGradStops(0), m_NormFactor(-1.0), +m_InvNormFactor(-1.0) //m_ProcessRangesMinInkUptake(NULL),m_ProcessRangesMinP(NULL), //m_ProcessRangesMaxInkUptake(NULL) { m_whitepointLab.Set(-1, -1, -1); m_whitepointXYZ_Strip.Set(-1, -1, -1); m_whitepointXYZ_CT.Set(-1, -1, -1); - } Tango::ColorLib::ColorConverter::~ColorConverter() @@ -113,6 +115,11 @@ Tango::ColorLib::ColorConverter::~ColorConverter() delete[] m_ProcessRangesMaxP; m_ProcessRangesMaxP = NULL; } + if (m_GradStops != NULL) + { + delete[] m_GradStops; + m_GradStops = NULL; + } /* if (m_ProcessRangesMinP != NULL) { delete[] m_ProcessRangesMinP; @@ -217,6 +224,7 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(ConversionInput *conv //double * LabInFinal1 = DBG_NEW double[3]; double * LabInFinal2 = new double[3]; double * LabOnGamut = new double[3]; + double *InkOutP = new double[m_nB2AnSepOut]; bool InGamut = true; for (int i = 0; i < nHive; ++i) { @@ -224,30 +232,51 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(ConversionInput *conv for (j = 0; j < 3; ++j) Lab1P[j] = Lab1(i, j); //Check if whitepoints match - if (m_AdaptWP) +/* if (m_AdaptWP) { //Convert to CT whitepoint m_Conv02->ChangeWP(Lab1P, Lab1P, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); LimitLab(LabInFinal1); } - ColConv.ChangeWP(Lab1P, Lab1P, m_WP, m_whitepointXYZ_CT); //to Relative - + */ +// ColConv.ChangeWP(Lab1P, Lab1P, m_WP, m_whitepointXYZ_CT); //to Relative + ColConv.ChangeWP(Lab1P, Lab1P, m_WP, m_whitepointXYZ_Strip); //to Relative m_B2ATransform->evalLab2InkP(Lab1P, InkOut, GamutRegion[i]); //InkOut is in units of 16 bits + for (int i = 0; i < m_nB2AnSepOut; ++i) + { + InkOut[i] *= m_NormFactor; + if (InkOut[i] <= m_GamutRegionMaxLim[0]) + { + m_LinCurves->m_InterpCurves[i].Eval(InkOut[i] * 655.35, InkOut[i]); + InkOut[i] /= 655.35; + } + } InGamut = IsInGamut(Lab1P, sur, CS, LabOnGamut); LimitLab(LabOnGamut); + VectorXd NLInkOut(m_nB2AnSepOut); + ConvertToNLInks(DoubleToVector(InkOut, m_nInks), NLInkOut); + + //Limit inks based on m_maxNlpercm + //Inks are limited in their nonlinear form + //Output Volume is in % + LimitInks(NLInkOut, InkOutP); + NLInkPToVolume(DoubleToVector(InkOutP, m_nInks), Vol); + GamutRegion[i] = GetGamutRegion(Vol, m_ProcessRangesMaxP); + NLcmtoPercentage(Vol, Vol); //m_A2BTransform->evalInkP2Lab(InkOut, Lab1P, GamutRegion[i]); //Convert to CT WP - m_Conv02->ChangeWP(LabOnGamut, LabInFinal1, m_whitepointXYZ_CT, m_WP); //convert back to Absolute +// m_Conv02->ChangeWP(LabOnGamut, LabInFinal1, m_whitepointXYZ_CT, m_WP); //convert back to Absolute + m_Conv02->ChangeWP(LabOnGamut, LabInFinal1, m_whitepointXYZ_Strip, m_WP); //convert back to Absolute LimitLab(LabInFinal1); //Absolute //Check if whitepoints match - if (m_AdaptWP) +/* if (m_AdaptWP) { //Convert to Strip whitepoint m_Conv02->ChangeWP(LabInFinal1, LabInFinal1, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); LimitLab(LabInFinal1); - } + }*/ m_Conv02->SetReferenceWhite(D65); for (int j = 0; j < 3; ++j) LabHive(i, j) = LabInFinal1[j]; @@ -257,32 +286,7 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(ConversionInput *conv //m_Conv02->LabtoRGB(Lab1P, tmpRGB); for (int j = 0; j < 3; ++j) RGBTmpVec(i, j) = std::min(std::max(tmpRGB[j], 0.0), 255.0); - - double NormFactor = m_ProcessRangesMaxP[m_nProcessRanges - 1] / 100.0; - for (int j = 0; j < m_nB2AnSepOut; ++j) - { - InkOut[j] *= NormFactor; - if (InkOut[j] <= m_ProcessRangesMaxP[0]) - { - m_LinCurves->m_InterpCurves[j].Eval(InkOut[j] * 655.35, InkOut[j]); - InkOut[j] /= 655.35; - } - } - - VectorXd InkOutV = DoubleToVector(InkOut, m_nInks); - - ConvertToNLInks(InkOutV, InkOutV); - double maxNLInk = NegValue; - for (int j = 0; j < m_nInks; ++j) - maxNLInk = std::max(InkOutV(j), maxNLInk); - - for (int j = 0; j < (int)(conversionInput->n_processranges - 1); ++j) - { - if (maxNLInk > m_ProcessRangesMaxP[j]) - GamutRegion[i]++; - } - - NLInkPToVolume(InkOutV, Vol); + //make sure the rounded sum does not exceed the limit in the gamut region for (int j = 0; j < m_nInks; ++j) VolumeHive(i, j) = Vol(j); @@ -348,6 +352,11 @@ void Tango::ColorLib::ColorConverter::ProcessHiveNeighbors(ConversionInput *conv delete[]LabInFinal1; LabInFinal1 = NULL; } + if (InkOutP != NULL) + { + delete[] InkOutP; + InkOutP = NULL; + } return; } @@ -443,6 +452,10 @@ void Tango::ColorLib::ColorConverter::ArrangeHiveData(MatrixXd LabHive, MatrixX } } + + + + void Tango::ColorLib::ColorConverter::fillVolume(OutputCoordinates *&outputCoords, VectorXd Volume) { int i = 0; @@ -493,29 +506,39 @@ void Tango::ColorLib::ColorConverter::fillLab(OutputCoordinates *outputCoords, V outputCoords->has_b = true; outputCoords->b = LabOut(2); } - void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* conversionInput) { + SetStripWhitepoint(conversionInput->threadl, conversionInput->threada, conversionInput->threadb); + bool has_forwarddata = conversionInput->has_forwarddata; + uint8_t *data = conversionInput->forwarddata.data; + int nprocessranges = conversionInput->n_processranges; + readColorTables(has_forwarddata, data, nprocessranges); + +} + +void Tango::ColorLib::ColorConverter::SetStripWhitepoint(double threadl, double threada, double threadb) +{ //Read thread white. Thread White is given in CIELab Space - m_whitepointLab.Set(conversionInput->threadl, conversionInput->threada, conversionInput->threadb); + m_whitepointLab.Set(threadl, threada, threadb); //White point in XYZ Color Space ColorConvert CConvert(D65, D65); C_RGB_XYZ_Lab tmpW; tmpW = CConvert.LabToXYZ(m_whitepointLab); m_whitepointXYZ_Strip.Set(tmpW.Get_x(), tmpW.Get_y(), tmpW.Get_z()); +} - - +void Tango::ColorLib::ColorConverter::readColorTables(bool has_data, uint8_t * data, int nprocessranges) +{ //parse Color Tansformations, placed in forward data int bytesread = 0; NumConversions conv; int tag_count = 0; - if (conversionInput->has_forwarddata) + if (has_data) { //Read Header - CT_Header header = read_header(conversionInput, bytesread); + CT_Header header = read_header(data, bytesread); SetnGamutRegions((int)header.nGamutRegions); - if (m_nGamutRegions != conversionInput->n_processranges) + if (m_nGamutRegions != nprocessranges) { throw std::exception("Number of gamut regions in table does not match STRIP\0"); return; @@ -523,7 +546,7 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* m_GamutRegionMaxLim = new double[m_nGamutRegions]; for (int i = 0; i < m_nGamutRegions; ++i) m_GamutRegionMaxLim[i] = header.GRegMaxLim[i]; - m_nProcessRanges = (int)(conversionInput->n_processranges); + m_nProcessRanges = (int)(nprocessranges); /* for (int i = 0; i < m_nGamutRegions; ++i) { @@ -539,7 +562,7 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* uint32_t tmp; - uint8_t *buff = conversionInput->forwarddata.data; + uint8_t *buff =data; tmp = conv.ByteToInt(buff, bytesread); tag_count = (int)tmp; bytesread += 4; @@ -602,7 +625,7 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* { case A2B: { - uint8_t *A2BLUT = &(conversionInput->forwarddata.data[TagSize[k][0]]); + uint8_t *A2BLUT = &(data[TagSize[k][0]]); int A2BLutsize = TagSize[k][1]; m_A2BTransform = new ColorTransf(); //m_A2BTransform = DBG_NEW ColorTransf(); @@ -611,7 +634,7 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* } case B2A: { - uint8_t *B2ALUT = &(conversionInput->forwarddata.data[TagSize[k][0]]); + uint8_t *B2ALUT = &(data[TagSize[k][0]]); int B2ALutsize = TagSize[k][1]; m_B2ATransform = new ColorTransf(); //m_B2ATransform = DBG_NEW ColorTransf(); @@ -629,7 +652,7 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* } */ case gbd: { - uint8_t *GBDList = &(conversionInput->forwarddata.data[TagSize[k][0]]); + uint8_t *GBDList = &(data[TagSize[k][0]]); m_GBD = new GBD(); //m_GBD = DBG_NEW GBD(); int GBDSize = TagSize[k][1]; @@ -638,7 +661,7 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* } case lcrv: { - uint8_t *CurvesData = &(conversionInput->forwarddata.data[TagSize[k][0]]); + uint8_t *CurvesData = &(data[TagSize[k][0]]); m_LinCurves = new Curves(); int CurvesSize = TagSize[k][1]; m_LinCurves->InitData(CurvesData, CurvesSize); @@ -646,20 +669,20 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* } case wtpt: { - read_xyz_type(TagSize[k][0], TagSize[k][1], &m_whitepointXYZ_CT, conversionInput); + read_xyz_type(TagSize[k][0], TagSize[k][1], &m_whitepointXYZ_CT, data); break; } case cprt: { std::string textstr; - read_text_type(TagSize[k][0], TagSize[k][1], &textstr, conversionInput); + read_text_type(TagSize[k][0], TagSize[k][1], &textstr, data); break; } case desc: { std::string textdescstr; - read_text_description_type(TagSize[k][0], TagSize[k][1], textdescstr, conversionInput); + read_text_description_type(TagSize[k][0], TagSize[k][1], textdescstr, data); break; } default: @@ -744,19 +767,19 @@ void Tango::ColorLib::ColorConverter::readColorTransformations(ConversionInput* } -void Tango::ColorLib::ColorConverter::readCalibrationTables(ConversionInput* conversionInput) +void Tango::ColorLib::ColorConverter::readCalibrationTables(InputLiquid **inputliquid, int n_inputliquid) { - SetNumberofInks((int)(conversionInput->inputcoordinates->n_inputliquids)); + SetNumberofInks((int)(n_inputliquid)); //CalibData *CalibCurves = new CalibData[m_nInks]; m_CalibCurves = new CalibData[m_nInks]; //m_CalibCurves = DBG_NEW CalibData[m_nInks]; for (int i = 0; i < m_nInks; ++i) { - InputLiquid* InkType = conversionInput->inputcoordinates->inputliquids[i]; + InputLiquid* InkType = inputliquid[i]; m_CalibCurves[i].SetCalibName((int)(InkType->calibrationdata->liquidtype)); - m_CalibCurves[i].SetMaxNlPerCM(conversionInput->inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter); + m_CalibCurves[i].SetMaxNlPerCM(inputliquid[i]->maxnanoliterpercentimeter); switch (InkType->calibrationdata->liquidtype) { case LIQUID_TYPE__Cyan: @@ -821,7 +844,8 @@ void Tango::ColorLib::ColorConverter::SetCalibData(CalibrationData *calibrationD return; } -void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* conversionInput, VectorXd &InkOut, VectorXd &RGBOut, +void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(InputCoordinates* inputcoordinates, ColorSpace colorspace, + VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion, bool &InGamut) { size_t nInks = 0; @@ -829,7 +853,7 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* C_RGB_XYZ_Lab DataLab; SURROUND sur = m_Conv02->getSurround(); CAM02CS CS = m_Conv02->getCAM02CS(); - switch (conversionInput->colorspace) + switch (colorspace) { case (COLOR_SPACE__RGB): { @@ -843,9 +867,9 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* //4. Convert Lab to Absolute colorimetric taking into account the Strip and Color Table whitepoints //5. Use the Relative Colorimetric Lab to obtain RGB - RGBOut(0) = conversionInput->inputcoordinates->red; - RGBOut(1) = conversionInput->inputcoordinates->green; - RGBOut(2) = conversionInput->inputcoordinates->blue; + RGBOut(0) = inputcoordinates->red; + RGBOut(1) = inputcoordinates->green; + RGBOut(2) = inputcoordinates->blue; //convert to Lab ColorConvert CConvertD65(D65, D65); //Destination, source double *LabIn = new double[3]; @@ -867,19 +891,18 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* double *InkOutP = new double[m_nB2AnSepOut]; //double *InkOutP = DBG_NEW double[m_nB2AnSepOut]; //LabInFinal is in Relative Colorimetric, just like the Color Tables - m_B2ATransform->evalLab2InkP(LabOnGamut, InkOutP, GamutRegion); //InkOut is in units of 16 bits + m_B2ATransform->evalLab2InkP(LabOnGamut, InkOutP, GamutRegion); //InkOut is inthe [0-100] interval //Convert to Lab to get the actual in Gamut Lab //double *LabInP = new double[3]; //double *LabInP = DBG_NEW double[3]; //m_A2BTransform->evalInkP2Lab(InkOutP, LabInP, GamutRegion); //Lab is in Relative Colorimetric - double NormFactor = m_ProcessRangesMaxP[m_nProcessRanges - 1] / 100.0; //Convert InkOut to Linear via initial calibration Tables //Initial calibration tables are the ones that were included in the color table for (int i = 0; i < m_nB2AnSepOut; ++i) { - InkOutP[i] *= NormFactor; - if (InkOutP[i] <= m_ProcessRangesMaxP[0]) + InkOutP[i] *= m_NormFactor; + if (InkOutP[i] <= m_GamutRegionMaxLim[0]) { m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]); InkOutP[i] /= 655.35; @@ -888,13 +911,16 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* InkOut = DoubleToVector(InkOutP, m_nInks); //Convert to CT thread, LabOnGamut is in Relative Colorimetric Space - CConvertD65.ChangeWP(LabOnGamut, LabInFinal, m_whitepointXYZ_CT, m_WP); + //CConvertD65.ChangeWP(LabOnGamut, LabInFinal, m_whitepointXYZ_CT, m_WP); + CConvertD65.ChangeWP(LabOnGamut, LabInFinal, m_whitepointXYZ_Strip, m_WP); //check if the thread to be used is the same as the one in the color tables + /* if (m_AdaptWP) { //Convert to Strip White Point CConvertD65.ChangeWP(LabInFinal, LabInFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); } + */ LabOut = DoubleToVector(LabInFinal, 3); CConvertD65.SetReferenceWhite(D65); double *RGBOutP1 = new double[3]; @@ -945,28 +971,31 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* //5. Use the Relative Colorimetric Lab to obtain RGB double *LabIn = new double[3]; //double *LabIn = DBG_NEW double[3]; - LabIn[0] = conversionInput->inputcoordinates->l; //Absolute Colorimetric - LabIn[1] = conversionInput->inputcoordinates->a; - LabIn[2] = conversionInput->inputcoordinates->b; + LabIn[0] = inputcoordinates->l; //Absolute Colorimetric + LabIn[1] = inputcoordinates->a; + LabIn[2] = inputcoordinates->b; //the assumption is that the color space has illumination that matches the whitepoint of the Strip ColorConvert CConvertD65(D65, D65); //Destination, source - double *LabInFinal1 = new double[3]; + // double *LabInFinal1 = new double[3]; //double *LabInFinal1 = DBG_NEW double[3]; - for (int i = 0; i < 3; ++i) - LabInFinal1[i] = LabIn[i]; + // for (int i = 0; i < 3; ++i) + // LabInFinal1[i] = LabIn[i]; //LabInFinal1 = LabIn; // Lab is assumed to match the color of the STRIP, however the tables could have a different WP //Check if Color Tables and Strip whitepoints are the same, otherwise convert - if (m_AdaptWP) + /* + if (m_AdaptWP) { CConvertD65.ChangeWP(LabInFinal1, LabInFinal1, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); //to Color Tables for (int i = 0; i < 3; ++i) LabIn[i] = LabInFinal1[i]; } + */ double *LabInFinal2 = new double[3]; double *LabOnGamut = new double[3]; //double *LabInFinal2 = DBG_NEW double[3]; - CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_CT); //LabInFinal2 is in Relative Colorimetric Space +// CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_CT); //LabInFinal2 is in Relative Colorimetric Space + CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip); //LabInFinal2 is in Relative Colorimetric Space InGamut = IsInGamut(LabInFinal2, sur, CS, LabOnGamut); LimitLab(LabOnGamut); @@ -978,12 +1007,11 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* //Convert Inks to Lab to get the Gamut Mapped Lab //m_A2BTransform->evalInkP2Lab(InkOutP, LabIn, GamutRegion); //LabOut = DoubleToVector(LabIn, 3); - //Convert InkOutP to linear in the m_ProcessRangesMaxP[0] range - double NormFactor = m_ProcessRangesMaxP[m_nProcessRanges - 1] / 100.0; + //Convert InkOutP to linear in the m_GamutRegionMaxLim[0] range for (int i = 0; i < m_nB2AnSepOut; ++i) { - InkOutP[i] *= NormFactor; - if (InkOutP[i] <= m_ProcessRangesMaxP[0]) + InkOutP[i] *= m_NormFactor; + if (InkOutP[i] <= m_GamutRegionMaxLim[0]) { m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]); InkOutP[i] /= 655.35; @@ -996,11 +1024,14 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* LabOutFinal[i] = LabOnGamut[i]; //LabOutFinal is in Relative Colorimetric //Reverse the conversion process to bring back Lab to STRIP white point - CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_CT, m_WP); +// CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_CT, m_WP); + CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_Strip, m_WP); +/* if (m_AdaptWP) { CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); } + */ LabOut = DoubleToVector(LabOutFinal, 3); CConvertD65.SetReferenceWhite(D65); //Convert to RGB @@ -1025,11 +1056,12 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* delete[] LabIn; LabIn = NULL; } - if (LabInFinal1 != NULL) +/* if (LabInFinal1 != NULL) { delete[]LabInFinal1; LabInFinal1 = NULL; } + */ if (LabInFinal2 != NULL) { delete[]LabInFinal2; @@ -1056,10 +1088,10 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* double *outData = new double[m_nA2BnSepIn]; //double *outData = DBG_NEW double[m_nA2BnSepIn]; size_t CountSep = 0; - outData[0] = (double)(conversionInput->inputcoordinates->cyan); - outData[1] = (double)(conversionInput->inputcoordinates->magenta); - outData[2] = (double)(conversionInput->inputcoordinates->yellow); - outData[3] = conversionInput->inputcoordinates->key; + outData[0] = (double)(inputcoordinates->cyan); + outData[1] = (double)(inputcoordinates->magenta); + outData[2] = (double)(inputcoordinates->yellow); + outData[3] = (double)(inputcoordinates->key); CountSep = 4; if (CountSep != m_nA2BnSepIn) @@ -1090,13 +1122,15 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* LabOutFinal2[i] = LabOutP[i]; InGamut = true; //Check if white points match - CConvertD65.ChangeWP(LabOutFinal1, LabOutFinal1, m_whitepointXYZ_CT, m_WP); //To Absolute - if (m_AdaptWP) +// CConvertD65.ChangeWP(LabOutFinal1, LabOutFinal1, m_whitepointXYZ_CT, m_WP); //To Absolute + CConvertD65.ChangeWP(LabOutFinal1, LabOutFinal1, m_whitepointXYZ_Strip, m_WP); //To Absolute +/* if (m_AdaptWP) { CConvertD65.ChangeWP(LabOutFinal1, LabOutFinal2, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); for (int i = 0; i < 3; ++i) LabOutFinal1[i] = LabOutFinal2[i]; } + */ LabOut = DoubleToVector(LabOutFinal1, 3); CConvertD65.SetReferenceWhite(D65); //Get RGB @@ -1141,8 +1175,8 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* case(COLOR_SPACE__Catalog): { int32_t inData; - if (conversionInput->inputcoordinates->has_pantoncode) - inData = conversionInput->inputcoordinates->pantoncode; + if (inputcoordinates->has_pantoncode) + inData = inputcoordinates->pantoncode; else { //mismatch between color space and data @@ -1156,7 +1190,7 @@ void Tango::ColorLib::ColorConverter::ConvertColorToLinearInks(ConversionInput* default: { throw std::exception(" Unsupported Color Space"); - return; + break; } } //all data is now in linear ink format @@ -1168,7 +1202,7 @@ void Tango::ColorLib::ColorConverter::ConvertToNLInks(VectorXd InkIn, VectorXd { for (int i = 0; i < m_nVolumes; ++i) { - if (InkIn(i) <= m_ProcessRangesMaxP[0]) + if (InkIn(i) <= m_GamutRegionMaxLim[0]) m_CalibCurves[i].m_InvLinearInterp->Eval(InkIn(i), InkOut(i)); else InkOut(i) = InkIn(i); @@ -1188,13 +1222,14 @@ void Tango::ColorLib::ColorConverter::ConvertToLinearInks(VectorXd InkIn, Vecto void Tango::ColorLib::ColorConverter::VolumeToNLInkP(VectorXd Volume, VectorXd &NLInkP) { + //Volume is in %. In order to be compatible with NL to volume it has to be tranlated to nl/cm VectorXd InkP(m_nVolumes); int MaxInd = -1; double InkMax = -1.; double InkSum = 0.; for (int i = 0; i < m_nVolumes; ++i) { - InkP(i) = Volume(i); /// 100 * Volume(i) / m_maxNlPerCM(i); //Volume is in % + InkP(i) = Volume(i)* m_maxNlPerCM(i)/100; //Volume is in %, InkP is in [nl/cm] if (InkMax < InkP(i)) { InkMax = InkP(i); @@ -1202,7 +1237,7 @@ void Tango::ColorLib::ColorConverter::VolumeToNLInkP(VectorXd Volume, VectorXd & } InkSum += InkP(i); } - NLInkP(MaxInd) = InkSum; + NLInkP(MaxInd) =100* InkSum/ m_maxNlPerCM(MaxInd); //Back to % if (InkSum == 0.0) { for (int i = 0; i < m_nVolumes; ++i) @@ -1245,7 +1280,7 @@ void Tango::ColorLib::ColorConverter::VolumeToNLInkP(VectorXd Volume, VectorXd & if (i != MaxInd) { ind += 1; - NLInkP(i) = Result(ind); + NLInkP(i) =100* Result(ind)/m_maxNlPerCM(i); //Back to % } } return; @@ -1286,7 +1321,7 @@ void Tango::ColorLib::ColorConverter::NLInkPToVolume(VectorXd NLInk, VectorXd &V RVolNorm(i) = round(Volume(i)*ROUNDINGTol) / ROUNDINGTol; RsumNorm += RVolNorm(i); } - if (RsumNorm > m_ProcessRangesMaxP[m_nProcessRanges - 1] || abs(sumNorm - RsumNorm) >= 1 / ROUNDINGTol) + if (RsumNorm > m_GamutRegionMaxLim[m_nProcessRanges - 1] || abs(sumNorm - RsumNorm) >= 1 / ROUNDINGTol) { VectorXd dd(m_nInks); double maxdd = -1; @@ -1379,9 +1414,10 @@ void Tango::ColorLib::ColorConverter::SetMaxNLperCM(double maxNlPerCM, int i) m_maxNlPerCM(i) = maxNlPerCM; } -void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(ConversionInput* conversionInput, VectorXd &Volume, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion) +void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(InputCoordinates *inputcoordinates, int n_processRanges, + int colorspace, VectorXd &Volume, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion) { - SetNumberOfVolumes((int)(conversionInput->inputcoordinates->n_inputliquids)); + SetNumberOfVolumes((int)(inputcoordinates->n_inputliquids)); // Set Calibration Data LiquidType LQ; if (m_CalibCurves == NULL) @@ -1390,46 +1426,45 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(ConversionInput* //m_CalibCurves = DBG_NEW CalibData[m_nInks]; for (int i = 0; i < m_nVolumes; ++i) { - LQ = conversionInput->inputcoordinates->inputliquids[i]->calibrationdata->liquidtype; + LQ =inputcoordinates->inputliquids[i]->calibrationdata->liquidtype; if (LQ == LIQUID_TYPE__Cyan || LQ == LIQUID_TYPE__Magenta || LQ == LIQUID_TYPE__Yellow || LQ == LIQUID_TYPE__Black) { //Get calibration data. - CalibrationData* calibrationData = conversionInput->inputcoordinates->inputliquids[i]->calibrationdata; + CalibrationData* calibrationData = inputcoordinates->inputliquids[i]->calibrationdata; SetCalibData(calibrationData, i, &m_CalibCurves[i]); - SetMaxNLperCM(conversionInput->inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter, i); - m_CalibCurves[i].SetCalibName((int)(conversionInput->inputcoordinates->inputliquids[i]->calibrationdata->liquidtype)); + SetMaxNLperCM(inputcoordinates->inputliquids[i]->maxnanoliterpercentimeter, i); + m_CalibCurves[i].SetCalibName((int)(inputcoordinates->inputliquids[i]->calibrationdata->liquidtype)); } else std::exception("unsupported volume"); } } + + //July 29 2020 + //Limit inks based on m_maxNlpercm + //Inks are limited in their nonlinear form VectorXd NLInkP((int)(m_nVolumes)); VectorXd InkOut((int)(m_nVolumes)); //Convert to Nonlinear Inks double SumVol_Ink = 0.0; + //Get Gamut Region for (int i = 0; i < m_nVolumes; ++i) - { - Volume(i) = conversionInput->inputcoordinates->inputliquids[i]->volume; //volume is given in % - SumVol_Ink += Volume(i); - } - for (int i = 0; i < int(conversionInput->n_processranges - 1); ++i) - { - if (SumVol_Ink > m_ProcessRangesMaxP[i]) - GamutRegion++; - } + Volume(i) = inputcoordinates->inputliquids[i]->volume; //volume is given in % + + GamutRegion = GetGamutRegion(Volume, m_GamutRegionMaxLim); VolumeToNLInkP(Volume, NLInkP); + //Limit Inks double *InkOutP = new double[m_nA2BnSepIn]; VectorToDouble(NLInkP, InkOutP); //for (int i = 0; i < m_nA2BnSepIn; ++i) // InkOutP[i] = NLInkP(i); double *LinInkP = new double[m_nA2BnSepIn]; - double NormFactor = 100 / m_ProcessRangesMaxP[m_nProcessRanges - 1]; - - if (conversionInput->colorspace == COLOR_SPACE__Catalog) +//Reflect the Calibration Curves of the thread in Catalog Items + if (colorspace == COLOR_SPACE__Catalog) { for (int i = 0; i < m_nB2AnSepOut; ++i) { - if (NLInkP(i) <= m_ProcessRangesMaxP[0]) + if (NLInkP(i) <= m_GamutRegionMaxLim[0]) { m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]); InkOutP[i] /= 655.35; @@ -1439,15 +1474,24 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(ConversionInput* } for (int i = 0; i < (int)(m_nVolumes); ++i) { - if (NLInkP(i) <= m_ProcessRangesMaxP[0]) + if (NLInkP(i) <= m_GamutRegionMaxLim[0]) { m_CalibCurves[i].m_InvLinearInterp->Eval(InkOutP[i], InkOutP[i]); NLInkP(i) = InkOutP[i]; } } - NLInkPToVolume(NLInkP, Volume); + //NLInkPToVolume(NLInkP, Volume); } + //July 29 2020 + //Limit inks based on m_maxNlpercm + //Inks are limited in their nonlinear form + //Output Volume is in % + LimitInks(NLInkP, InkOutP); + NLInkPToVolume(DoubleToVector(InkOutP, m_nInks), Volume); + GamutRegion = GetGamutRegion(Volume, m_ProcessRangesMaxP); + NLcmtoPercentage(Volume, Volume); + //Convert to RGB //GamutRegion = 0; //Convert to Lab @@ -1457,7 +1501,7 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(ConversionInput* //double *LabOutP = DBG_NEW double[m_nA2BnSepOut]; //InkOutP has to be normalized to match the transform units for (int i = 0; i < m_nB2AnSepOut; ++i) - InkOutP[i] *= NormFactor; + InkOutP[i] *= m_InvNormFactor; m_A2BTransform->evalInkP2Lab(InkOutP, LabOutP, GamutRegion); @@ -1467,14 +1511,17 @@ void Tango::ColorLib::ColorConverter::ConvertVolumeToRGBDisplay(ConversionInput* //double *LabOutFinal1 = DBG_NEW double[3]; double *LabOutFinal = new double[3]; - CConvertD65.ChangeWP(LabOutP, LabOutFinal1, m_whitepointXYZ_CT, m_WP); //To Absolute + //CConvertD65.ChangeWP(LabOutP, LabOutFinal1, m_whitepointXYZ_CT, m_WP); //To Absolute + CConvertD65.ChangeWP(LabOutP, LabOutFinal1, m_whitepointXYZ_Strip, m_WP); //To Absolute for (int i = 0; i < 3; ++i) LabOutFinal[i] = LabOutFinal1[i]; +/* if (m_AdaptWP) { CConvertD65.ChangeWP(LabOutFinal, LabOutFinal, m_whitepointXYZ_Strip, m_whitepointXYZ_CT); } + */ LabOut = DoubleToVector(LabOutFinal, 3); CConvertD65.SetReferenceWhite(D65); @@ -1605,10 +1652,10 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i //count number if inks // int numofInks = CountNumberofInks(conversionInput); readColorTransformations(conversionInput); - //read calibration tables and store them in m_CalibCurves - - readCalibrationTables(conversionInput); + InputLiquid **inputliquids = conversionInput->inputcoordinates->inputliquids; + int n_inputliquids = conversionInput->inputcoordinates->n_inputliquids; + readCalibrationTables(inputliquids, n_inputliquids); //Initialize CIECAM02 transformation Illum IL = D65; @@ -1623,27 +1670,24 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i SetNumberOfInks(m_nB2AnSepOut); // Compare Strip White point to Color Table White Point - CompareWhitePoints(); + //CompareWhitePoints(); if (numofInks != m_nB2AnSepOut) throw std::exception("Number of available inks does not match ink tables\0"); //Tables have been filled - - //Convert maxInkUptake to percentages - - //m_ProcessRangesMinP = new double[m_nProcessRanges]; + //Set Process Ranges m_ProcessRangesMaxP = new double[m_nProcessRanges]; - //m_ProcessRangesMinInkUptake = new double[m_nProcessRanges]; - //m_ProcessRangesMaxInkUptake = new double[m_nProcessRanges]; for (int i = 0; i < m_nProcessRanges; ++i) { - // m_ProcessRangesMinP[i] = 100*(conversionInput->processranges[i]->mininkuptake)/ (conversionInput->processranges[0]->mininkuptake); - m_ProcessRangesMaxP[i] = 100 * (conversionInput->processranges[i]->maxinkuptake) / (conversionInput->processranges[0]->maxinkuptake); - //m_ProcessRangesMinInkUptake[i] = conversionInput->processranges[i]->mininkuptake; - //m_ProcessRangesMaxInkUptake[i] = conversionInput->processranges[i]->maxinkuptake; + m_ProcessRangesMaxP[i] = conversionInput->processranges[i]->maxinkuptake; + } + NormGamutRegionMaxLim(); + if (m_NormFactor <= 0.0) + { + SetNormFactor(); + SetInverseNormFactor(); } - VectorXd InkOut(m_nB2AnSepOut); VectorXd RGBOut(3); VectorXd LabOut(3); @@ -1661,28 +1705,34 @@ size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t i //Convert input data to linear inks if (conversionInput->colorspace == COLOR_SPACE__Volume || conversionInput->colorspace == COLOR_SPACE__Catalog) { - ConvertVolumeToRGBDisplay(conversionInput, Volume, RGBOut, LabOut, GamutRegion); + InputCoordinates *IC = conversionInput->inputcoordinates; + int colorspace = conversionInput->colorspace; + ConvertVolumeToRGBDisplay(IC, conversionInput->n_processranges, colorspace, Volume, RGBOut, LabOut, GamutRegion); InGamut = true; } else { - ConvertColorToLinearInks(conversionInput, InkOut, RGBOut, LabOut, GamutRegion, InGamut); + ConvertColorToLinearInks(conversionInput->inputcoordinates, conversionInput->colorspace, InkOut, RGBOut, + LabOut, GamutRegion, InGamut); //Inks are in Linear Space , convert to nonlinear by using Calibration Tables, // Right now calibration is in the [0-100] range, values exceeding [0-100] are not transformed ConvertToNLInks(InkOut, NLInkOut); - //Determine Gamut Region - double maxNLInk = NegValue; - for (int i = 0; i < m_nInks; ++i) - maxNLInk = std::max(NLInkOut[i], maxNLInk); - - for (int i = 0; i < int(conversionInput->n_processranges - 1); ++i) + + //Limit inks based on m_maxNlpercm + //Inks are limited in their nonlinear form + //Output Volume is in % + double *InkOutP = new double[m_nB2AnSepOut]; + LimitInks(NLInkOut, InkOutP); + NLInkPToVolume(DoubleToVector(InkOutP, m_nInks), Volume); + GamutRegion = GetGamutRegion(Volume, m_ProcessRangesMaxP); + NLcmtoPercentage(Volume, Volume); + //OutputCoordinates outputCoords = OUTPUT_COORDINATES__INIT; + if (InkOutP != NULL) { - if (maxNLInk > m_ProcessRangesMaxP[i]) - GamutRegion++; + delete[] InkOutP; + InkOutP = NULL; } - //Convert to [nl/cm] - NLInkPToVolume(NLInkOut, Volume); - //OutputCoordinates outputCoords = OUTPUT_COORDINATES__INIT; + } OutputCoordinates *outputCoords = (OutputCoordinates*)malloc(sizeof(OutputCoordinates)); output_coordinates__init(outputCoords); @@ -1975,14 +2025,14 @@ bool Tango::ColorLib::ColorConverter::IsInGamut(double *InLab, SURROUND sur, CA } -Tango::CT_Header Tango::ColorLib::ColorConverter::read_header(ConversionInput* conversionInput, int &bytesread) +Tango::CT_Header Tango::ColorLib::ColorConverter::read_header(uint8_t *data, int &bytesread) { //CT_Header *Header = new CT_Header; //CT_Header *Header = DBG_NEW CT_Header; CT_Header Header; // unsigned int tmp = (buffer[2 * i + 1] << 8) | buffer[2 * i]; - uint8_t *ColorTable = conversionInput->forwarddata.data; + uint8_t *ColorTable =data; //File Size NumConversions Conv; Header.TblSIze = Conv.ByteToInt(ColorTable, bytesread); @@ -2088,7 +2138,7 @@ void Tango::ColorLib::ColorConverter::read_lut_type(int offset, int data_size, C return; } -void Tango::ColorLib::ColorConverter::read_xyz_type(int offset, int data_size, C_RGB_XYZ_Lab *XYZ, ConversionInput* conversionInput) +void Tango::ColorLib::ColorConverter::read_xyz_type(int offset, int data_size, C_RGB_XYZ_Lab *XYZ, uint8_t *data) { // 0 - 3 'XYZ ' //4 - 7 reserved, must be 0 @@ -2098,7 +2148,7 @@ void Tango::ColorLib::ColorConverter::read_xyz_type(int offset, int data_size, C { throw std::exception("not enough data to read xyz"); } - uint8_t *buff = &(conversionInput->forwarddata.data[offset]); + uint8_t *buff = &(data[offset]); NumConversions Conv; int bytesread = 0; int tmpxyz = Conv.ByteToInt(buff, bytesread); @@ -2145,8 +2195,7 @@ void Tango::ColorLib::ColorConverter::read_xyz_type(int offset, int data_size, C return; } -void Tango::ColorLib::ColorConverter::read_text_type(int offset, int data_size, std::string *textstr, - ConversionInput* conversionInput) +void Tango::ColorLib::ColorConverter::read_text_type(int offset, int data_size, std::string *textstr, uint8_t *data) { // 0 - 3 'text' //4 - 7 reserved, must be 0 @@ -2161,7 +2210,7 @@ void Tango::ColorLib::ColorConverter::read_text_type(int offset, int data_size, return; } - uint8_t *buff = &(conversionInput->forwarddata.data[offset]); + uint8_t *buff = &(data[offset]); int bytesread = 0; NumConversions Conv; int tmp = Conv.ByteToInt(buff, bytesread); @@ -2201,15 +2250,14 @@ void Tango::ColorLib::ColorConverter::read_text_type(int offset, int data_size, } -void Tango::ColorLib::ColorConverter::read_text_description_type(int offset, int data_size, std::string textdescstr, - ConversionInput* conversionInput) +void Tango::ColorLib::ColorConverter::read_text_description_type(int offset, int data_size, std::string textdescstr, uint8_t *data) { // 0 - 3 'desc' // 4 - 7 reserved, must be 0 // 8 - 11 ASCII invariant description count, including terminating NULL // 12 - ASCII invariant description - uint8_t *buff = &(conversionInput->forwarddata.data[offset]); + uint8_t *buff = &(data[offset]); int bytesread = 0; NumConversions Conv; int tmp = Conv.ByteToInt(buff, bytesread); @@ -2251,7 +2299,7 @@ void Tango::ColorLib::ColorConverter::read_text_description_type(int offset, int return; } -void Tango::ColorLib::ColorConverter::CompareWhitePoints() +/*void Tango::ColorLib::ColorConverter::CompareWhitePoints() { ColorConvert ColConv(D65, D65); C_RGB_XYZ_Lab Lab_CT; @@ -2270,10 +2318,10 @@ void Tango::ColorLib::ColorConverter::CompareWhitePoints() ColConv.SymmetricaldECMC(VLab_CT, VLab_Strip, dECMC); if (dECMC > WPTol) m_AdaptWP = true; - if (m_whitepointXYZ_Strip.Get_x() <= 0 || m_whitepointXYZ_Strip.Get_y() > 0 || m_whitepointXYZ_Strip.Get_z()) + if (m_whitepointXYZ_Strip.Get_x() <= 0 || m_whitepointXYZ_Strip.Get_y() <= 0 || m_whitepointXYZ_Strip.Get_z()<=0) m_AdaptWP = false; return; -} +} */ /* not used*/ //size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer) //{ @@ -2479,8 +2527,9 @@ size_t Tango::ColorLib::ColorConverter::P_IsInGamut(uint8_t * input_buffer, size readColorTransformations(conversionInput); //read calibration tables and store them in m_CalibCurves - - readCalibrationTables(conversionInput); + int n_inputliquids = conversionInput->inputcoordinates->n_inputliquids; + InputLiquid **inputliquid = conversionInput->inputcoordinates->inputliquids; + readCalibrationTables(inputliquid, n_inputliquids); //Initialize CIECAM02 transformation Illum IL = D65; @@ -2495,7 +2544,7 @@ size_t Tango::ColorLib::ColorConverter::P_IsInGamut(uint8_t * input_buffer, size SetNumberOfInks(m_nB2AnSepOut); // Compare Strip White point to Color Table White Point - CompareWhitePoints(); + //CompareWhitePoints(); if (numofInks != m_nB2AnSepOut) throw std::exception("Number of available inks does not match ink tables"); @@ -2561,19 +2610,22 @@ size_t Tango::ColorLib::ColorConverter::P_IsInGamut(uint8_t * input_buffer, size LabIn[2] = conversionInput->inputcoordinates->b; //the assumption is that the color space has illumination that matches the whitepoint of the Strip ColorConvert CConvertD65(D65, D65); //Destination, source - double *LabInFinal1 = new double[3]; +// double *LabInFinal1 = new double[3]; //double *LabInFinal1 = DBG_NEW double[3]; - for (int i = 0; i < 3; ++i) - LabInFinal1[i] = LabIn[i]; +// for (int i = 0; i < 3; ++i) +// LabInFinal1[i] = LabIn[i]; // Lab is assumed to match the color of the STRIP, however the tables could have a different WP - //Check if Color Tables and Strip whitepoints are the same, otherwise convert + //We relate to the color table as a generic one in Relative Colorimetric Space + /* if (m_AdaptWP) { CConvertD65.ChangeWP(LabInFinal1, LabInFinal1, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); //to Color Tables } + */ double *LabInFinal2 = new double[3]; //double *LabInFinal2 = DBG_NEW double[3]; - CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_CT); //to Relative + // CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_CT); //to Relative + CConvertD65.ChangeWP(LabIn, LabInFinal2, m_WP, m_whitepointXYZ_Strip); //to Relative InGamut = IsInGamut(LabInFinal2, sur, CS, LabInFinal2); LimitLab(LabInFinal2); @@ -2582,11 +2634,11 @@ size_t Tango::ColorLib::ColorConverter::P_IsInGamut(uint8_t * input_buffer, size delete[] LabIn; LabIn = NULL; } - if (LabInFinal1 != NULL) + /* if (LabInFinal1 != NULL) { delete[]LabInFinal1; LabInFinal1 = NULL; - } + } */ if (LabInFinal2 != NULL) { delete[]LabInFinal2; @@ -2651,16 +2703,20 @@ size_t Tango::ColorLib::ColorConverter::P_IsInGamut(uint8_t * input_buffer, size size_t Tango::ColorLib::ColorConverter::GenerateGradient(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer) { - //Get Input... GradientConversionInput* conversionInput = (GradientConversionInput*)malloc(sizeof(GradientConversionInput)); conversionInput = gradient_conversion_input__unpack(NULL, input_buffer_size, input_buffer); + //Initialize Output... + GradientConversionOutput *conversionOutput = (GradientConversionOutput*)malloc(sizeof(GradientConversionOutput)); + gradient_conversion_output__init(conversionOutput); + conversionOutput->haserror = false; + conversionOutput->has_haserror = false; //Get segment length... double segmentLength = conversionInput->segmentlength; - + PrepareGradient(conversionInput, conversionOutput); //Get liquid types info... - InputLiquid* cyan = NULL; +/* InputLiquid* cyan = NULL; InputLiquid* magenta = NULL; InputLiquid* yellow = NULL; InputLiquid* black = NULL; @@ -2682,137 +2738,762 @@ size_t Tango::ColorLib::ColorConverter::GenerateGradient(uint8_t * input_buffer, black = conversionInput->inputliquids[i]; break; } - } + }*/ - //Iterate over input stops... - for (size_t i = 0; i < conversionInput->n_stops; i++) - { - GradientInputStop* stop = conversionInput->stops[i]; - stop->colorspace; //Stop color space. - stop->offset; // Stop offset within the segment length (0-1) + //Pack output... + output_buffer = (uint8_t*)malloc(gradient_conversion_output__get_packed_size(conversionOutput)); + int size = gradient_conversion_output__pack(conversionOutput, output_buffer); + + //RELEASE MEMORY HERE !!! +#pragma region Free Conversion Input & Output + + gradient_conversion_input__free_unpacked(conversionInput, NULL); + + gradient_conversion_output__free_unpacked(conversionOutput, NULL); - switch (stop->colorspace) +#pragma endregion + + return size; +} + +void Tango::ColorLib::ColorConverter::fillGradientStops(GradientConversionInput *conversionInput) +{ + for (int i = 0; i < m_nGradStops; ++i) + { + switch (conversionInput->stops[i]->colorspace) { case COLOR_SPACE__RGB: //Case RGB - stop->red; - stop->green; - stop->blue; + m_GradStops[i].RGB.Set(conversionInput->stops[i]->red, conversionInput->stops[i]->green, conversionInput->stops[i]->blue); + m_GradStops[i].colorspace = COLOR_SPACE__RGB; + m_GradStops[i].offset = conversionInput->stops[i]->offset; break; case COLOR_SPACE__LAB: //Case LAB - stop->l; - stop->a; - stop->b; + m_GradStops[i].Lab.Set(conversionInput->stops[i]->l, conversionInput->stops[i]->a, conversionInput->stops[i]->b); + m_GradStops[i].colorspace = COLOR_SPACE__LAB; + m_GradStops[i].offset = conversionInput->stops[i]->offset; break; case COLOR_SPACE__Volume: //Case Volume - - double cyanVolume = 0; - double magentaVolume = 0; - double yellowVolume = 0; - double blackVolume = 0; - - for (size_t j = 0; j < stop->n_liquidvolumes; j++) + m_GradStops[i].colorspace = COLOR_SPACE__Volume; + m_GradStops[i].offset = conversionInput->stops[i]->offset; + for (int j = 0; j < (int)conversionInput->stops[i]->n_liquidvolumes; j++) { - LiquidVolume* liquidVolume = stop->liquidvolumes[j]; + LiquidVolume* liquidVolume = conversionInput->stops[i]->liquidvolumes[j]; switch (liquidVolume->liquidtype) { case LIQUID_TYPE__Cyan: - cyanVolume = liquidVolume->volume; + m_GradStops[i].Volume[0] = liquidVolume->volume; + break; case LIQUID_TYPE__Magenta: - magentaVolume = liquidVolume->volume; + m_GradStops[i].Volume[1] = liquidVolume->volume; + break; case LIQUID_TYPE__Yellow: - yellowVolume = liquidVolume->volume; + m_GradStops[i].Volume[2] = liquidVolume->volume; + break; case LIQUID_TYPE__Black: - blackVolume = liquidVolume->volume; + m_GradStops[i].Volume[3] = liquidVolume->volume; + break; + default: + throw std::exception("could not fill all volumes"); } } - break; } } +} - //Initialize Output... - GradientConversionOutput *conversionOutput = (GradientConversionOutput*)malloc(sizeof(GradientConversionOutput)); - gradient_conversion_output__init(conversionOutput); - int stops_count = 100; +void Tango::ColorLib::ColorConverter::findStops(GradStruct m_GradStop1, GradStruct m_GradStop2, double dEThr, int ninterstops, + int &nOut, double **VecRGBOut, double **VecLabOut, double *posOut) +{ + ColorConvert CConvertD65(D65, D65); + C_RGB_XYZ_Lab RGBStart = m_GradStop1.RGB; + C_RGB_XYZ_Lab RGBEnd = m_GradStop2.RGB; + C_RGB_XYZ_Lab LowLab(0, -128, -128); + C_RGB_XYZ_Lab HighLab(100, 127, 127); + C_RGB_XYZ_Lab LowRGB(0, 0, 0); + C_RGB_XYZ_Lab HighRGB(255, 255, 255); + + int nsubdiv = 100; + C_RGB_XYZ_Lab dRGB((RGBEnd.Get_x() - RGBStart.Get_x()) / nsubdiv, (RGBEnd.Get_y() - RGBStart.Get_y()) / nsubdiv, + (RGBEnd.Get_z() - RGBStart.Get_z()) / nsubdiv); + + + C_RGB_XYZ_Lab *VecLabOut_tmp = new C_RGB_XYZ_Lab[ninterstops]; + C_RGB_XYZ_Lab *VecRGBOut_tmp = new C_RGB_XYZ_Lab[ninterstops]; + C_RGB_XYZ_Lab *VecLabOut_fin = new C_RGB_XYZ_Lab[ninterstops]; + C_RGB_XYZ_Lab *VecRGBOut_fin = new C_RGB_XYZ_Lab[ninterstops]; + C_RGB_XYZ_Lab RGBTmp; + C_RGB_XYZ_Lab LabTmp; + // make a vector of RGB values with 100 subdivisions + // make a matching Lab vector; + + VecRGBOut_tmp[0] = C_RGB_XYZ_Lab(RGBStart); + VecLabOut_tmp[0] = C_RGB_XYZ_Lab(m_GradStop1.Lab); + + for (int i = 1; i <= nsubdiv; ++i) + { + VecRGBOut_tmp[i].Set(VecRGBOut_tmp[i - 1].Get_x() + dRGB.Get_x(), + VecRGBOut_tmp[i - 1].Get_y() + dRGB.Get_y(), + VecRGBOut_tmp[i - 1].Get_z() + dRGB.Get_z()); + VecLabOut_tmp[i] = CConvertD65.RGBtoLab(VecRGBOut_tmp[i]); + VecLabOut_tmp[i].Clamp(LowLab, HighLab); + } + + int indGrad = 0; + int *pos = new int[ninterstops]; + int i1 = 1; + int j1 = 1; + VecLabOut_fin[indGrad] = VecLabOut_tmp[0]; + VecRGBOut_fin[indGrad] = VecRGBOut_tmp[0]; + pos[indGrad] = 0; + double dE = 0.0; + double dEOld = 0.0; + while (i1 <= nsubdiv) + { + dEOld = dE; + CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[i1], dE); + j1 = i1; + while (dE < dEThr && i1 < nsubdiv && j1 < nsubdiv) + { + j1++; + dEOld = dE; + CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[j1], dE); + } + if (j1 > i1) + { + j1--; + indGrad++; + VecRGBOut_fin[indGrad] = VecRGBOut_tmp[j1]; + VecLabOut_fin[indGrad] = VecLabOut_tmp[j1]; + pos[indGrad] = j1; + dE = dEOld; + i1 = j1 + 1; + } + else + { + dEOld = dE; + while (dE >= dEThr && i1 <= nsubdiv) + { + //get intermediate point + RGBTmp = VecRGBOut_tmp[i1]; + LabTmp = CConvertD65.RGBtoLab(RGBTmp); + LabTmp.Clamp(LowLab, HighLab); + //move vectors down by one + for (int i = i1; i < nsubdiv; ++i) + { + VecRGBOut_tmp[i + 1] = VecRGBOut_tmp[i + 1]; + VecLabOut_tmp[i + 1] = VecLabOut_tmp[i + 1]; + } + VecRGBOut_tmp[i1] = RGBTmp; + VecLabOut_tmp[i1] = LabTmp; + CConvertD65.dEcmc(VecLabOut_fin[indGrad], VecLabOut_tmp[i1], dE); + nsubdiv++; + } + indGrad++; + VecRGBOut_fin[indGrad] = VecRGBOut_tmp[j1]; + VecLabOut_fin[indGrad] = VecLabOut_tmp[j1]; + pos[indGrad] = j1; + i1 = j1 + 1; + } + } + nOut = indGrad; + + for (int i = 0; i < nOut; ++i) + { + VecLabOut[i][0] = VecLabOut_fin[i].Get_x(); + VecLabOut[i][1] = VecLabOut_fin[i].Get_y(); + VecLabOut[i][2] = VecLabOut_fin[i].Get_z(); + VecRGBOut[i][0] = VecRGBOut_fin[i].Get_x(); + VecRGBOut[i][1] = VecRGBOut_fin[i].Get_y(); + VecRGBOut[i][2] = VecRGBOut_fin[i].Get_z(); + posOut[i] = pos[i]; + } + //free allocs + if(VecLabOut_tmp != NULL) + { + delete[] VecLabOut_tmp; + VecLabOut_tmp = NULL; + } + if (VecRGBOut_tmp != NULL) + { + delete[] VecRGBOut_tmp; + VecRGBOut_tmp = NULL; + } + if (VecLabOut_fin != NULL) + { + delete[] VecLabOut_fin; + VecLabOut_fin = NULL; + } + if (VecRGBOut_fin != NULL) + { + delete[] VecRGBOut_fin; + VecRGBOut_fin = NULL; + } + if (pos != NULL) + { + delete[] pos; + pos = NULL; + } +} + +void Tango::ColorLib::ColorConverter::ConvertGradStoptoVolume(InputCoordinates* inputcoordinates, ColorSpace colorspace, + VectorXd &Volume, int &GamutRegion) +{ + size_t nInks = 0; + + C_RGB_XYZ_Lab DataLab; + VectorXd InkOut(m_nB2AnSepOut); + if (colorspace ==COLOR_SPACE__RGB) + { + //Convert RGB to Volume, no nee to calculate RGBOut and LabOut + // Basic assumption: if data is given in RGB space, conversion should be in relative colorimetric, + //We expect that [255,255,255](white) will be mapped to the thread white, meaning all inks should be zero + // and the coverted RGB will refect the color of the thread, but will be shown in Relative Colorimetric to the user + + //convert to Lab + ColorConvert CConvertD65(D65, D65); //Destination, source + double *LabIn = new double[3]; + double *RGBOutP = new double[3]; + RGBOutP[0] = inputcoordinates->red; + RGBOutP[1] = inputcoordinates->green; + RGBOutP[2] = inputcoordinates->blue; + //RGB to Lab + CConvertD65.RGBtoLab(RGBOutP, LabIn); //Values are in Relative Colorimetric, D65 + LimitLab(LabIn); + + //convert to inks + int GamutRegion; + double *InkOutP = new double[m_nB2AnSepOut]; + m_B2ATransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in units of 16 bits + + //Convert InkOut to Linear via initial calibration Tables + //Initial calibration tables are the ones that were included in the color table + for (int i = 0; i < m_nB2AnSepOut; ++i) + { + InkOutP[i] *= m_NormFactor; + if (InkOutP[i] <= m_GamutRegionMaxLim[0]) + { + m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]); + InkOutP[i] /= 655.35; + } + } + InkOut = DoubleToVector(InkOutP, m_nInks); + + if (InkOutP != NULL) + { + delete[] InkOutP; + InkOutP = NULL; + } + if (LabIn != NULL) + { + delete[] LabIn; + LabIn = NULL; + } + if (RGBOutP != NULL) + { + delete[] RGBOutP; + RGBOutP = NULL; + } + } + else if(colorspace ==COLOR_SPACE__LAB) + { + // Basic assumption: Lab data is in relative colorimetric. No Need to convert + + double *LabIn = new double[3]; + LabIn[0] = inputcoordinates->l; //Relative Colorimetric + LabIn[1] = inputcoordinates->a; + LabIn[2] = inputcoordinates->b; - //Init output stops array... - GradientOutputStop** outputStops = (GradientOutputStop**)malloc(sizeof(GradientOutputStop*) * stops_count); + //convert to Inks + int GamutRegion; + double *InkOutP = new double[m_nB2AnSepOut]; + m_B2ATransform->evalLab2InkP(LabIn, InkOutP, GamutRegion); //InkOut is in the [0-100] interval + for (int i = 0; i < m_nB2AnSepOut; ++i) + { + InkOutP[i] *= m_NormFactor; + if (InkOutP[i] <= m_GamutRegionMaxLim[0]) + { + m_LinCurves->m_InterpCurves[i].Eval(InkOutP[i] * 655.35, InkOutP[i]); + InkOutP[i] /= 655.35; + } + } + InkOut = DoubleToVector(InkOutP, m_nInks); - conversionOutput->stops = outputStops; - conversionOutput->n_stops = stops_count; + if (InkOutP != NULL) + { + delete[] InkOutP; + InkOutP = NULL; + } + if (LabIn != NULL) + { + delete[] LabIn; + LabIn = NULL; + } + } + else + { + throw std::exception("Unsupported Color Space"); + return; + } + VectorXd NLInkOut(m_nB2AnSepOut); + VectorXd VolumeOut(m_nB2AnSepOut); + double *InkOutL = new double[m_nB2AnSepOut]; + ConvertToNLInks(InkOut, NLInkOut); + LimitInks(NLInkOut, InkOutL); + NLInkPToVolume(DoubleToVector(InkOutL, m_nInks), Volume); + GamutRegion = GetGamutRegion(Volume, m_ProcessRangesMaxP); + NLcmtoPercentage(Volume, Volume); + if (InkOutL != NULL) + { + delete[] InkOutL; + InkOutL = NULL; + } - double fake_volume = 1; + return; +} + +void Tango::ColorLib::ColorConverter::SetNormFactor() +{ + m_NormFactor = m_GamutRegionMaxLim[m_nProcessRanges - 1] / m_GamutRegionMaxLim[0]; +} - //Put Demo Stops... - for (size_t i = 0; i < stops_count; i++) +void Tango::ColorLib::ColorConverter::SetInverseNormFactor() +{ + if (m_NormFactor <= 0) + m_InvNormFactor = -1; + else + m_InvNormFactor = 1.0 / m_NormFactor; +} + +void Tango::ColorLib::ColorConverter::PrepareGradient(GradientConversionInput* conversionInput, GradientConversionOutput *conversionOutput) +{ + //fill input stops... + m_nGradStops = conversionInput->n_stops; + m_GradStops = new GradStruct[m_nGradStops]; + InputCoordinates **inputcoordinates = (InputCoordinates**)malloc(sizeof(InputCoordinates*)*m_nGradStops); + double *InkOutL = new double[m_nB2AnSepOut]; + for (int i = 0; i < m_nGradStops; ++i) { - GradientOutputStop *stop = (GradientOutputStop*)malloc(sizeof(GradientOutputStop)); - gradient_output_stop__init(stop); + inputcoordinates[i] = (InputCoordinates*)malloc(sizeof(InputCoordinates)); + input_coordinates__init(inputcoordinates[i]); + } + m_nVolumes = conversionInput->stops[0]->n_liquidvolumes; + fillGradientStops(conversionInput); + GradInput2InputCoords(conversionInput, inputcoordinates); - stop->processparameterstableindex = 0; //Set process parameters table index (0,1). - stop->offset = (double)i / (double)stops_count; + //Global Parameters of gradient + SetStripWhitepoint(conversionInput->threadl, conversionInput->threada, conversionInput->threadb); + bool has_forwarddata = conversionInput->has_forwarddata; + uint8_t *data = conversionInput->forwarddata.data; + int nprocessranges = conversionInput->n_processranges; + readColorTables(has_forwarddata, data, nprocessranges); - //Init stop output liquids - OutputLiquid** outputLiquids = (OutputLiquid**)malloc(sizeof(OutputLiquid*) * 4); + int n_inputliquids = conversionInput->n_inputliquids; + InputLiquid **inputliquid = conversionInput->inputliquids; + readCalibrationTables(inputliquid, n_inputliquids); - //Init cyan. - OutputLiquid* c = (OutputLiquid*)malloc(sizeof(OutputLiquid)); - output_liquid__init(c); - c->has_liquidtype = true; - c->has_volume = true; - c->liquidtype = LIQUID_TYPE__Cyan; - c->volume = fake_volume++; - outputLiquids[0] = c; + //finished reading tables and data + //prepare data to construct the gradient + //gradient is calculated in RGB space, thinned out or expanded based on dE criteria + // returns a vector of volumes and offsets + //gradient stops in different gamut region will use regular transformation + //if all stops in gamut region 0 the color Table will be suited to this gamut region - //Init magenta. - OutputLiquid* m = (OutputLiquid*)malloc(sizeof(OutputLiquid)); - output_liquid__init(m); - m->has_liquidtype = true; - m->has_volume = true; - m->liquidtype = LIQUID_TYPE__Magenta; - m->volume = fake_volume++; - outputLiquids[1] = m; + //prepare input + //if Color Space = lab, fill rgb and calculate volume + volume region + //if color space = rgb, fill lab and calculate volue + volume region + //if color space = Volume, fill lab and RGB, calculate volume region - //Init yellow. - OutputLiquid* y = (OutputLiquid*)malloc(sizeof(OutputLiquid)); - output_liquid__init(y); - y->has_liquidtype = true; - y->has_volume = true; - y->liquidtype = LIQUID_TYPE__Yellow; - y->volume = fake_volume++; - outputLiquids[2] = y; + bool InGamut = false; + m_WP.Set(0.9505, 1.00, 1.0888); //D65 + //Initialize CIECAM02 transformation + Illum IL = D65; + SURROUND sur = average; + CAM02CS CS = UCS; + m_Conv02 = new ColorConvert(IL, IL, Y_b, L_A, sur, CS); + SetnA2BnSepIn(m_A2BTransform->GetSeparationsIn()); + SetnA2BnSepOut(m_A2BTransform->GetSeparationsOut()); + SetnB2AnSepIn(m_B2ATransform->GetSeparationsIn()); + SetnB2AnSepOut(m_B2ATransform->GetSeparationsOut()); + SetNumberOfInks(m_nB2AnSepOut); + // Compare Strip White point to Color Table White Point + //CompareWhitePoints(); + ColorConvert CConvertD65(D65, D65); //Destination, source + if (n_inputliquids != m_nInks) + throw std::exception("Number of available inks does not match ink tables\0"); - //Init black. - OutputLiquid* k = (OutputLiquid*)malloc(sizeof(OutputLiquid)); - output_liquid__init(k); - k->has_liquidtype = true; - k->has_volume = true; - k->liquidtype = LIQUID_TYPE__Black; - k->volume = fake_volume++; - outputLiquids[3] = k; + //Convert maxInkUptake to percentages + NormGamutRegionMaxLim(); + if (m_NormFactor <= 0.0) + { + SetNormFactor(); + SetInverseNormFactor(); + } + VectorXd InkOut(m_nB2AnSepOut); + VectorXd RGBOut(3); + VectorXd LabOut(3); + VectorXd NLInkOut(m_nB2AnSepOut); + VectorXd Volume(m_nB2AnSepOut); + VectorXd VolumeOut(m_nB2AnSepOut); + //set maxNlPerCM + VectorXd NlperCM(m_nB2AnSepOut); + double *LabOutV = new double[3]; + double *LabOutFinal = new double[3]; + NlperCM.setZero(); + m_maxNlPerCM = NlperCM; + for (int i = 0; i < m_nB2AnSepOut; ++i) + SetMaxNLperCM(conversionInput->inputliquids[i]->maxnanoliterpercentimeter, i); + m_nVolumes = m_nB2AnSepOut; + int GamutRegion = 0; + for (int i = 0; i < m_nGradStops; ++i) + { + if (m_GradStops[i].colorspace == COLOR_SPACE__Volume || m_GradStops[i].colorspace == COLOR_SPACE__Catalog) + { //Convert volume to Lab + //Convert lab to rgb + ConvertVolumeToRGBDisplay(inputcoordinates[i], m_nProcessRanges, m_GradStops[i].colorspace, Volume, RGBOut, LabOut, GamutRegion); + //store data + m_GradStops[i].Lab.Set(LabOut(0), LabOut(1), LabOut(2)); + m_GradStops[i].RGB.Set(RGBOut(0), RGBOut(1), RGBOut(2)); + m_GradStops[i].GamutRegion = GamutRegion; + m_GradStops[i].InGamut = true; + } + else + { + ConvertColorToLinearInks(inputcoordinates[i], m_GradStops[i].colorspace, InkOut, RGBOut, LabOut, GamutRegion, InGamut); + //Inks are in Linear Space , convert to nonlinear by using Calibration Tables, + // Right now calibration is in the [0-100] range, values exceeding [0-100] are not transformed - stop->outputliquids = outputLiquids; - stop->n_outputliquids = 4; + ConvertToNLInks(InkOut, NLInkOut); + LimitInks(NLInkOut, InkOutL); + NLInkPToVolume(DoubleToVector(InkOutL, m_nInks), Volume); + GamutRegion = GetGamutRegion(Volume, m_ProcessRangesMaxP); + NLcmtoPercentage(Volume, Volume); + + //fill data + //fill volume + //allocate m_GradStops[i].Volume + m_GradStops[i].Volume = new double[m_nB2AnSepOut]; + for (int j = 0; j < m_nB2AnSepOut; ++j) + m_GradStops[i].Volume[j] = Volume[j]; + m_GradStops[i].GamutRegion = GamutRegion; + m_GradStops[i].InGamut = InGamut; + //LabOut and RGBOut might be different if the input was out of gamut + m_GradStops[i].Lab.Set(LabOut(0), LabOut(1), LabOut(2)); + m_GradStops[i].RGB.Set(RGBOut(0), RGBOut(1), RGBOut(2)); + } + //Convert Lab Values to Relative Colorimetric. These values will be used in the Gradient Volume calculation. + VectorToDouble(LabOut, LabOutV); +/* if (m_AdaptWP) + { + CConvertD65.ChangeWP(LabOutV, LabOutV, m_whitepointXYZ_CT, m_whitepointXYZ_Strip); //to Color Tables + } + */ + //double *LabInFinal2 = DBG_NEW double[3]; +// CConvertD65.ChangeWP(LabOutV, LabOutFinal, m_WP, m_whitepointXYZ_CT); //LabInFinal is in Relative Colorimetric Space + CConvertD65.ChangeWP(LabOutV, LabOutFinal, m_WP, m_whitepointXYZ_Strip); //LabInFinal is in Relative Colorimetric Space + m_GradStops[i].Lab.Set(LabOutFinal[0], LabOutFinal[1], LabOutFinal[2]); + } + //free vectors + if (LabOutV == NULL) + { + delete[] LabOutV; + LabOutV = NULL; + } + if (LabOutFinal == NULL) + { + delete[] LabOutFinal; + LabOutFinal = NULL; + } + if (InkOutL == NULL) + { + delete[] InkOutL; + InkOutL = NULL; + } - outputStops[i] = stop; + //are all stops in the same region? + int maxreg = -10; + int minreg = 10; + for (int i = 0; i < m_nGradStops; ++i) + { + maxreg = std::max(maxreg, m_GradStops[i].GamutRegion); + minreg = std::min(minreg, m_GradStops[i].GamutRegion); + } + bool same_regions = true; + if (maxreg != minreg) + same_regions = false; + double dEThr = 0.8; + //find intermediate points + int ninterstops = 300; + double **VecRGBOut = new double*[ninterstops]; + double **VecLabOut = new double*[ninterstops]; + double *posOut = new double[ninterstops]; + for (int i = 0; i < ninterstops; ++i) + { + VecLabOut[i] = new double[3]; + VecRGBOut[i] = new double[3]; } + int nOut = 0; + int nmaxstops = ninterstops * m_nGradStops; - //Pack output... - output_buffer = (uint8_t*)malloc(gradient_conversion_output__get_packed_size(conversionOutput)); - int size = gradient_conversion_output__pack(conversionOutput, output_buffer); + //Allocate temporary storage for all stops and positions + double **AllRGBOut_tmp = new double*[nmaxstops]; + double **AllLabOut_tmp = new double*[nmaxstops]; + double *AllPos_tmp = new double[nmaxstops]; + for (int i = 0; i < nmaxstops; ++i) + { + AllRGBOut_tmp[i] = new double[3]; + AllLabOut_tmp[i] = new double[3]; + } + AllRGBOut_tmp[0][0] = m_GradStops[0].RGB.Get_x(); + AllRGBOut_tmp[0][1] = m_GradStops[0].RGB.Get_y(); + AllRGBOut_tmp[0][2] = m_GradStops[0].RGB.Get_z(); + AllLabOut_tmp[0][0] = m_GradStops[0].Lab.Get_x(); + AllLabOut_tmp[0][1] = m_GradStops[0].Lab.Get_y(); + AllLabOut_tmp[0][2] = m_GradStops[0].Lab.Get_z(); + AllPos_tmp[0] = m_GradStops[0].offset; + int ncountStops = 0; + int nPosStops = 0; + double dOffset = 0; + GradOffset OffsetType = EqSpaced; + for (int i = 0; i < m_nGradStops - 1; ++i) + { + findStops(m_GradStops[i], m_GradStops[i + 1], dEThr, ninterstops, nOut, VecRGBOut, VecLabOut, posOut); + if (i == m_nGradStops - 2) + dOffset = (m_GradStops[i + 1].offset - m_GradStops[i].offset)*GradientEndThr / (nOut - 1); + else + dOffset = (m_GradStops[i + 1].offset - m_GradStops[i].offset) / (nOut - 1); - //RELEASE MEMORY HERE !!! + switch (OffsetType) + { + case EqSpaced: + for (int j = 1; j < nOut; ++j) + { + nPosStops++; + AllPos_tmp[nPosStops] = m_GradStops[i].offset + dOffset * posOut[j]; + } + break; + case dESpaced: + for (int j = 0; j < nOut; ++j) + { + nPosStops++; + AllPos_tmp[nPosStops] = m_GradStops[i].offset + dOffset * j; + } + break; + } + //store the stops in temporary vector + for (int i = 1; i < nOut; ++i) + { + ncountStops++; + for (int j = 0; j < 3; ++j) + { + AllRGBOut_tmp[ncountStops][j] = VecRGBOut[i][j]; + AllLabOut_tmp[ncountStops][j] = VecLabOut[i][j]; + } + } + } -#pragma region Free Conversion Input & Output - - gradient_conversion_input__free_unpacked(conversionInput, NULL); + if (VecRGBOut != NULL) + { + for (int i = 0; i < nOut; ++i) + delete[]VecRGBOut[i]; + delete[]VecRGBOut; + } + if (VecLabOut != NULL) + { + for (int i = 0; i < nOut; ++i) + delete[]VecLabOut[i]; + delete[]VecLabOut; + VecLabOut = NULL; + } + if (VecLabOut != NULL) + { + delete[]posOut; + posOut = NULL; + } - gradient_conversion_output__free_unpacked(conversionOutput, NULL); + //Store Gradient intermediate data in Input Coordinates type structure. + //Simplify calculations, we only need the ink values, input values are in RGB color space + // Use table according to Gamut Regions, all stops in region 0, use 100%table otherwise use regular table, decrease dyeing speed. -#pragma endregion + int nTotalStops = ncountStops; + InputCoordinates **SubStops = (InputCoordinates**)malloc(sizeof(InputCoordinates*)*nTotalStops); - return size; + //Calculate and store + for (int i = 0; i < nTotalStops; ++i) + { + SubStops[i] = (InputCoordinates*)malloc(sizeof(InputCoordinates)); + input_coordinates__init(SubStops[i]); + SubStops[i]->l = AllLabOut_tmp[i][0]; + SubStops[i]->a = AllLabOut_tmp[i][1]; + SubStops[i]->b = AllLabOut_tmp[i][2]; + SubStops[i]->red = (int)round(AllRGBOut_tmp[i][0]); + SubStops[i]->green = (int)round(AllRGBOut_tmp[i][1]); + SubStops[i]->blue = (int)round(AllRGBOut_tmp[i][2]); + } + +GradientOutputStop** outputStops = (GradientOutputStop**)malloc(sizeof(GradientOutputStop*) * nTotalStops); +conversionOutput->stops = outputStops; +conversionOutput->n_stops = nTotalStops; + +ColorSpace SubStopsCS = COLOR_SPACE__LAB; +//double NormFactor = m_ProcessRangesMaxP[m_nProcessRanges - 1] / 100.0; +VectorXd VolumeStop(m_nB2AnSepOut); +for (int i = 0; i < ncountStops; ++i) +{ + GradientOutputStop *stop = (GradientOutputStop*)malloc(sizeof(GradientOutputStop)); + gradient_output_stop__init(stop); + ConvertGradStoptoVolume(SubStops[i], SubStopsCS, + VolumeStop, GamutRegion); + //start filling Output + fillStop(stop, VolumeStop, GamutRegion, AllPos_tmp[i]); + outputStops[i] = stop; } +//release memory +if(AllLabOut_tmp != NULL) +{ + for (int i = 0; i < nmaxstops; ++i) + delete[] AllLabOut_tmp[i]; + delete[] AllLabOut_tmp; + AllLabOut_tmp = NULL; +} +if (AllRGBOut_tmp != NULL) +{ + for (int i = 0; i < nmaxstops; ++i) + delete[] AllRGBOut_tmp[i]; + delete[] AllRGBOut_tmp; + AllRGBOut_tmp = NULL; +} +if (AllPos_tmp != NULL) +{ + delete[] AllPos_tmp; + AllPos_tmp = NULL; +} + + +for (int i=0; i< m_nGradStops; ++i) + input_coordinates__free_unpacked(inputcoordinates[i], NULL); +free(inputcoordinates); +inputcoordinates = NULL; +for (int i = 0; i < nTotalStops; ++i) + input_coordinates__free_unpacked(SubStops[i], NULL); +free(SubStops); +SubStops = NULL; + +} + +void Tango::ColorLib::ColorConverter::NormGamutRegionMaxLim() +{ + double GamutRegionMaxLim0 = m_GamutRegionMaxLim[0]; + for (int i = 0; i < m_nProcessRanges; ++i) + m_GamutRegionMaxLim[i] = 100 * m_GamutRegionMaxLim[i] / GamutRegionMaxLim0; +} + +void Tango::ColorLib::ColorConverter::fillStop(GradientOutputStop *&stop, VectorXd Volume, int GamutRegion, double Position) +{ + OutputLiquid** outputLiquids = (OutputLiquid**)malloc(sizeof(OutputLiquid*) * m_nVolumes); + for (int i = 0; i < m_nVolumes; ++i) + { + outputLiquids[i] = (OutputLiquid*)malloc(sizeof(OutputLiquid)); + output_liquid__init(outputLiquids[i]); + switch (m_CalibCurves[i].getInkName()) + { + case LIQUID_TYPE__Cyan: + case LIQUID_TYPE__Magenta: + case LIQUID_TYPE__Yellow: + case LIQUID_TYPE__Black: + { + outputLiquids[i]->has_volume = true; + outputLiquids[i]->has_liquidtype = true; + outputLiquids[i]->liquidtype = (LiquidType)(m_CalibCurves[i].getInkName()); + outputLiquids[i]->volume = Volume(i); + break; + } + default: + throw std::exception("could not fill all volumes"); + } + } + stop->outputliquids = outputLiquids; + stop->n_outputliquids = m_nVolumes; + stop->has_processparameterstableindex = true; + stop->processparameterstableindex = GamutRegion; + stop->has_offset = true; + stop->offset = Position; +} + +void Tango::ColorLib::ColorConverter::GradInput2InputCoords(GradientConversionInput *conversionInput, InputCoordinates **inputcoordinates) +{ + for (size_t i = 0; i < conversionInput->n_stops; i++) + { + switch (conversionInput->stops[i]->colorspace) + { + case COLOR_SPACE__RGB: //Case RGB + inputcoordinates[i]->red = conversionInput->stops[i]->red; + inputcoordinates[i]->green = conversionInput->stops[i]->green; + inputcoordinates[i]->blue = conversionInput->stops[i]->blue; + inputcoordinates[i]->has_red = true; + inputcoordinates[i]->has_green = true; + inputcoordinates[i]->has_blue = true; + break; + case COLOR_SPACE__LAB: //Case LAB + inputcoordinates[i]->l = conversionInput->stops[i]->l; + inputcoordinates[i]->a = conversionInput->stops[i]->a; + inputcoordinates[i]->b = conversionInput->stops[i]->b; + inputcoordinates[i]->has_l = true; + inputcoordinates[i]->has_a = true; + inputcoordinates[i]->has_b = true; + break; + case COLOR_SPACE__Volume: //Case Volume + for (int j = 0; j < (int)conversionInput->stops[i]->n_liquidvolumes; j++) + { + LiquidVolume* liquidVolume = conversionInput->stops[i]->liquidvolumes[j]; + + switch (liquidVolume->liquidtype) + { + case LIQUID_TYPE__Cyan: + inputcoordinates[i]->inputliquids[0]->liquidtype = LIQUID_TYPE__Cyan; + inputcoordinates[i]->inputliquids[0]->volume = liquidVolume->volume; + case LIQUID_TYPE__Magenta: + inputcoordinates[i]->inputliquids[1]->liquidtype = LIQUID_TYPE__Magenta; + inputcoordinates[i]->inputliquids[1]->volume = liquidVolume->volume; + case LIQUID_TYPE__Yellow: + inputcoordinates[i]->inputliquids[2]->liquidtype = LIQUID_TYPE__Yellow; + inputcoordinates[i]->inputliquids[2]->volume = liquidVolume->volume; + case LIQUID_TYPE__Black: + inputcoordinates[i]->inputliquids[3]->liquidtype = LIQUID_TYPE__Black; + inputcoordinates[i]->inputliquids[3]->volume = liquidVolume->volume; + } + } + break; + } + } +} + +void Tango::ColorLib::ColorConverter::LimitInks(VectorXd inInks, double *BoundedInks) +{ + //convert Ink % to [nl/cm] + //Bound Ink + for (int i = 0; i < m_nInks; ++i) + BoundedInks[i] = std::min(inInks(i)*m_maxNlPerCM(i)/100.0, m_ProcessRangesMaxP[m_nProcessRanges - 1]); +} + +void Tango::ColorLib::ColorConverter::NLcmtoPercentage(VectorXd InVolume, VectorXd &OutVolume) +{ + for (int i = 0; i < m_nInks; ++i) + OutVolume(i) =100* InVolume(i) / m_maxNlPerCM(i); +} + +int Tango::ColorLib::ColorConverter::GetGamutRegion(VectorXd Volume, double *GamutLimits) +{ + double TotalVolume = 0.0; + int GamutRegion = 0; + for (int i = 0; i < m_nInks; ++i) + TotalVolume += Volume(i); + for (int i=0; i<m_nGamutRegions; ++i) + { + if (TotalVolume > GamutLimits[i]) + GamutRegion++; + } + return(GamutRegion); +}
\ No newline at end of file diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h index 96eeac0f9..15e8f2d04 100644 --- a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h +++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/ColorConverter.h @@ -11,6 +11,10 @@ #include "ConversionOutput.pb-c.h" #include "CalibrationData.pb-c.h" #include "ConversionInput.pb-c.h" +#include "GradientInputStop.pb-c.h" +#include "GradientOutputStop.pb-c.h" +#include "GradientConversionInput.pb-c.h" +#include "GradientConversionOutput.pb-c.h" #include "Interp.h" #include "Curves.h" @@ -29,12 +33,28 @@ namespace Tango double *GRegMaxLim; } CT_Header; - typedef enum { + typedef struct + { + C_RGB_XYZ_Lab Lab; + C_RGB_XYZ_Lab RGB; + double *Volume; + bool InGamut; + int GamutRegion; + double offset; + ColorSpace colorspace; + }GradStruct; + + /*typedef enum { XYZ, Lab, CMY, CMYK - }ColorSpace; + }ColorSpaceH;*/ + + typedef enum { + EqSpaced, + dESpaced + }GradOffset; typedef enum { A2B, @@ -49,17 +69,19 @@ namespace Tango namespace ColorLib { - - class ColorConverter { public: ColorConverter(); ~ColorConverter(); // size_t Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer); - void ConvertColorToLinearInks(ConversionInput* conversionInput, VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut, + void ConvertColorToLinearInks( InputCoordinates* inputcoordinates, ColorSpace colorspace, + VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion, bool &InGamut); - void ConvertVolumeToRGBDisplay(ConversionInput* conversionInput, VectorXd &InkOut, VectorXd &RGBOut, + void ConvertGradStoptoVolume(InputCoordinates* inputcoordinates, ColorSpace colorspace, + VectorXd &InkOut, int &GamutRegion); + void ConvertVolumeToRGBDisplay(InputCoordinates *IC, int n_processRanges,int colorspace, + VectorXd &InkOut, VectorXd &RGBOut, VectorXd &LabOut, int &GamutRegion); size_t Tango::ColorLib::ColorConverter::Convert(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer); size_t Tango::ColorLib::ColorConverter::GenerateGradient(uint8_t * input_buffer, size_t input_buffer_size, uint8_t *& output_buffer); @@ -83,18 +105,22 @@ namespace Tango C_RGB_XYZ_Lab m_whitepointXYZ_CT; void LimitLab(double* LabIn); int m_nGamutRegions; + int m_nGradStops; + GradStruct *m_GradStops; double *m_GamutRegionMaxLim; int m_nB2AnSepIn; int m_nB2AnSepOut; int m_nA2BnSepIn; int m_nA2BnSepOut; - bool m_AdaptWP; +// bool m_AdaptWP; CalibData *m_CalibCurves; int m_nInks; int m_nVolumes; int m_nProcessRanges; //double *m_ProcessRangesMinP; double *m_ProcessRangesMaxP; + double m_NormFactor; + double m_InvNormFactor; //double *m_ProcessRangesMaxInkUptake; //double *m_ProcessRangesMinInkUptake; C_RGB_XYZ_Lab m_WP; @@ -105,7 +131,8 @@ namespace Tango void SetnA2BnSepOut(int nA2BnSepOut) { m_nA2BnSepOut = nA2BnSepOut; }; void SetnGamutRegions(int nGamutRegions) { m_nGamutRegions = nGamutRegions; }; void readColorTransformations(ConversionInput* conversionInput); - void readCalibrationTables(ConversionInput* conversionInput); + void readColorTables(bool has_rddata, uint8_t *data, int nprocessranges); + void readCalibrationTables(InputLiquid **inputliquids, int n_inputliquids); void SetCalibData(CalibrationData* calibrationData, int i, CalibData *tmpCurve); void SetNumberofInks(int nInks) { m_nInks = nInks; }; void SetNumberOfVolumes(int nVol) { m_nVolumes = nVol; }; @@ -114,6 +141,8 @@ namespace Tango void fillRGB(OutputCoordinates *outputCoords, VectorXd RGBOut); void fillLab(OutputCoordinates *outputCoords, VectorXd LabOut); void fillVolume(OutputCoordinates *&outputCoords, VectorXd Volume); + void fillStop(GradientOutputStop *&stop, VectorXd Volume, int GamutRegion, double Position); + void fillGradientStops(GradientConversionInput *conversionInput); void ProcessHiveNeighbors(ConversionInput *conversionInput, VectorXd LabC, VectorXd RGBC, VectorXd VolumeC, int InGamutRegion, MatrixXd &RGBOut, MatrixXd & LabOut, MatrixXd &VolumeOut, int nHive, int *&GamutRegion, int *indDataMax); @@ -122,17 +151,28 @@ namespace Tango MatrixXd &ORGBHive, MatrixXd &OVolumeHive, int *&OGamutRegion); void FindTriplet(VectorXd Lab, MatrixXd Lab1, int nHive, int*indDataMax); int CountNumberofInks(ConversionInput* conversionInput); + void SetStripWhitepoint(double threadl, double threada, double threadb); void VectorToDouble(VectorXd Vec, double *doub); VectorXd DoubleToVector(double *doub, int nSize); void CompareWhitePoints(); bool IsInGamut(double *InLab, SURROUND sur, CAM02CS CS, double *LabCoord); - CT_Header read_header(ConversionInput* conversionInput, int &bytesread); + CT_Header read_header(uint8_t* data, int &bytesread); void read_lut_type(int offset, int data_size, ColorTransf *Transf, ConversionInput* conversionInput); - void read_xyz_type(int offset, int data_size, C_RGB_XYZ_Lab *xyz, ConversionInput* conversionInput); + void read_xyz_type(int offset, int data_size, C_RGB_XYZ_Lab *xyz, uint8_t *data); void read_text_type(int offset, int data_size, std::string *textstr, - ConversionInput* conversionInput); + uint8_t *data); void read_text_description_type(int offset, int data_size, std::string textdescstr, - ConversionInput* conversionInput); + uint8_t *data); + void findStops(GradStruct m_GradStops1, GradStruct m_GradStops2, double dEThr, int ninterstops, int &nOut, + double **VecRGBOut, double **VecLabOut, double *posOut); + void SetNormFactor(); + void SetInverseNormFactor(); + void NormGamutRegionMaxLim(); + void GradInput2InputCoords(GradientConversionInput *conversionInput, InputCoordinates **inputcoordinates); + void PrepareGradient(GradientConversionInput* conversionInput, GradientConversionOutput *conversionOutput); + void LimitInks(VectorXd inInks, double *BoundedInks); + void NLcmtoPercentage(VectorXd InVolume, VectorXd &OutVolume); + int GetGamutRegion(VectorXd Volume, double *GamutLimits); }; } } diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorConvert.cpp b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorConvert.cpp index a0d773aee..19ffdf4b5 100644 --- a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorConvert.cpp +++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorConvert.cpp @@ -1078,6 +1078,13 @@ void ColorConvert::Jab_parameters(CAM02CS CS) dECMCVal = (dECMC1 + dECMC2) / 2; } + void ColorConvert::dEcmc(C_RGB_XYZ_Lab &refX, C_RGB_XYZ_Lab &samX, double &dECMC) + { + VectorXd refX1 = refX.Get(); + VectorXd samX1 = samX.Get(); + dEcmc(samX1, refX1, dECMC); + } + void ColorConvert::dEcmc(VectorXd refX, VectorXd samX, double &dECMC) { //dEcmc(refX, samX) calculates color difference CMC(2:1) in diff --git a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorConvert.h b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorConvert.h index aa1b323b1..e9bec9331 100644 --- a/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorConvert.h +++ b/Software/Visual_Studio/ColorLib/Tango.ColorLib_v4/Utils/ColorConvert.h @@ -90,6 +90,7 @@ class ColorConvert double *LabToJab(double* pColor, SURROUND sur); void InitCiecamParams(double Y_b, double L_A, SURROUND sur, CAM02CS CS); void dEcmc(VectorXd refX, VectorXd samX, double &dE); + void dEcmc(C_RGB_XYZ_Lab &refX, C_RGB_XYZ_Lab &samX, double &dE); void SymmetricaldECMC(VectorXd refX, VectorXd samX, double &dECMC); CAM02CS getCAM02CS() { return(m_CS); }; SURROUND getSurround() { return(m_sur); }; diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs index d4bb07a9b..c31c95800 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs @@ -34,6 +34,7 @@ namespace Tango.MachineStudio.RML.ViewModels private IAuthenticationProvider _authentication; private IActionLogManager _actionLogManager; private RmlDTO _rmlBeforeSave; + private static object _syncLock = new object(); private ObservablesContext _rmls_context; private ObservablesContext _active_context; @@ -45,6 +46,22 @@ namespace Tango.MachineStudio.RML.ViewModels set { _rmls = value; RaisePropertyChangedAuto(); } } + private ICollectionView _rmlssCollectionView; + /// <summary> + /// Gets or sets the RML collection view. + /// </summary> + public ICollectionView RmlsCollectionView + { + get { return _rmlssCollectionView; } + set + { + _rmlssCollectionView = value; + BindingOperations.EnableCollectionSynchronization(_rmlssCollectionView, _syncLock); + + RaisePropertyChangedAuto(); + } + } + private ObservableCollection<MediaMaterial> _materials; public ObservableCollection<MediaMaterial> Materials { @@ -171,6 +188,16 @@ namespace Tango.MachineStudio.RML.ViewModels set { _colorCalibrationVM = value; RaisePropertyChangedAuto(); } } + private String _RMLFilter; + /// <summary> + /// Gets or sets the job filter. + /// </summary> + public String RMLFilter + { + get { return _RMLFilter; } + set { _RMLFilter = value; RaisePropertyChangedAuto(); OnRMLFilterChanged(); } + } + /// <summary> /// Gets or sets the manage RML command. /// </summary> @@ -262,7 +289,6 @@ namespace Tango.MachineStudio.RML.ViewModels _rmls_context = ObservablesContext.CreateDefault(); Rmls = await new RmlsCollectionBuilder(_rmls_context).SetAll().WithLiquidFactors().WithMediaProperties().BuildAsync(); - //Load CCT file names... var ccts = await _rmls_context.Ccts.Select(x => new { @@ -283,6 +309,8 @@ namespace Tango.MachineStudio.RML.ViewModels }; } } + RmlsCollectionView = CollectionViewSource.GetDefaultView(Rmls); + RmlsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Rml.LastUpdated), ListSortDirection.Descending)); } private async void LoadActiveRML(String guid) @@ -653,6 +681,23 @@ namespace Tango.MachineStudio.RML.ViewModels ActiveProcessParametersTableView.Refresh(); } + private void OnRMLFilterChanged() + { + String filter = RMLFilter.ToLower(); + + RmlsCollectionView.Filter = (rml) => + { + Rml r = rml as Rml; + return String.IsNullOrWhiteSpace(filter) + || + r.Name.ToLower().Contains(filter) //Rml name + || + (r.MediaMaterial != null && r.MediaMaterial.Name.ToLower().Contains(filter)) // Material name + || + (r.Cct != null && r.Cct.FileName != null && r.Cct.FileName.ToString().Contains(filter)); //Cct.FileName + }; + } + private void RemoveLiquidFactor(LiquidTypesRml liquidFactor) { if (_notification.ShowQuestion("Removing this liquid factor will remove the liquid type association with the RML and will drop the calibration data. Are you sure?")) diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlsView.xaml index 288f00a3d..18af6bed5 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlsView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlsView.xaml @@ -22,6 +22,10 @@ <DockPanel Margin="100 100 100 50" MaxWidth="1200"> <Grid DockPanel.Dock="Top"> <Image Source="../Images/threads.png" Width="300" Margin="10" /> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 10 30"> + <materialDesign:PackIcon Kind="Magnify" Width="26" Height="26"/> + <TextBox Width="300" materialDesign:HintAssist.Hint="Search name, material,..." Text="{Binding RMLFilter,UpdateSourceTrigger=PropertyChanged}"></TextBox> + </StackPanel> </Grid> <Grid DockPanel.Dock="Bottom"> <StackPanel> diff --git a/Software/Visual_Studio/Tango.ColorLib.GradientTest.CLI/Program.cs b/Software/Visual_Studio/Tango.ColorLib.GradientTest.CLI/Program.cs index 811f53841..37d219757 100644 --- a/Software/Visual_Studio/Tango.ColorLib.GradientTest.CLI/Program.cs +++ b/Software/Visual_Studio/Tango.ColorLib.GradientTest.CLI/Program.cs @@ -20,54 +20,54 @@ namespace Tango.ColorLib.GradientTest.CLI GradientConversionInput input = new GradientConversionInput(); //CCT - input.ForwardData = ByteString.CopyFrom(File.ReadAllBytes(@"C:\Test\CMYKSylko.cct")); //TODO: Load CCT file from local drive. + input.ForwardData = ByteString.CopyFrom(File.ReadAllBytes(@"C:\Mirta\Matlab\Sylko_HV_IL350.cct")); //TODO: Load CCT file from local drive. //RML Liquid Factors input.InputLiquids.Add(new InputLiquid() { LiquidType = LiquidType.Cyan, CalibrationData = BL.Entities.Cat.CreateDemoCalibrationData(LiquidType.Cyan), - MaxNanoliterPerCentimeter = 2.34, + MaxNanoliterPerCentimeter = 175, }); input.InputLiquids.Add(new InputLiquid() { LiquidType = LiquidType.Magenta, CalibrationData = BL.Entities.Cat.CreateDemoCalibrationData(LiquidType.Magenta), - MaxNanoliterPerCentimeter = 2.34, + MaxNanoliterPerCentimeter = 175, }); input.InputLiquids.Add(new InputLiquid() { LiquidType = LiquidType.Yellow, CalibrationData = BL.Entities.Cat.CreateDemoCalibrationData(LiquidType.Yellow), - MaxNanoliterPerCentimeter = 2.34, + MaxNanoliterPerCentimeter = 175, }); input.InputLiquids.Add(new InputLiquid() { LiquidType = LiquidType.Black, CalibrationData = BL.Entities.Cat.CreateDemoCalibrationData(LiquidType.Black), - MaxNanoliterPerCentimeter = 2.34, + MaxNanoliterPerCentimeter =175, }); //Process Ranges input.ProcessRanges.Add(new ProcessRange() { - MinInkUptake = 200, - MaxInkUptake = 200, + MinInkUptake = 175, + MaxInkUptake = 175, }); input.ProcessRanges.Add(new ProcessRange() { - MinInkUptake = 200, - MaxInkUptake = 400, + MinInkUptake = 175, + MaxInkUptake = 350, }); //White Point - input.ThreadL = 1; - input.ThreadA = 2; - input.ThreadB = 3; + input.ThreadL = 92.7867 ; + input.ThreadA = -0.2519; + input.ThreadB = 0.6968; //Segment length input.SegmentLength = 1000; @@ -77,9 +77,9 @@ namespace Tango.ColorLib.GradientTest.CLI { ColorSpace = ColorSpace.Rgb, Offset = 0, - Red = 255, - Green = 0, - Blue = 0, + Red = 25, + Green = 139, + Blue = 246, }); //RGB Stop 2 @@ -87,9 +87,9 @@ namespace Tango.ColorLib.GradientTest.CLI { ColorSpace = ColorSpace.Rgb, Offset = 1, - Red = 0, - Green = 0, - Blue = 255, + Red = 71, + Green = 244, + Blue = 40, }); Console.WriteLine($"Testing input:\n{input.ToJsonString(nameof(input.ForwardData),nameof(CalibrationData))}"); diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Analyzers/FlowAnalyser.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Analyzers/FlowAnalyser.cs index 2d4775a37..58c5dfedf 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Analyzers/FlowAnalyser.cs +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Analyzers/FlowAnalyser.cs @@ -11,6 +11,9 @@ using System.Linq.Expressions; using System.Diagnostics; using OxyPlot; using System.Collections.ObjectModel; +using Tango.Documents; +using System.IO; +using Tango.Core.Helpers; namespace Tango.DispenserAnalyzer.UI.Analyzers { @@ -38,7 +41,7 @@ namespace Tango.DispenserAnalyzer.UI.Analyzers if (index % 2 == 1)//testing Flow-error { - List<DispenserSample> filteredValues = rangeTestValues.Skip(1800).ToList(); + List<DispenserSample> filteredValues = rangeTestValues.Skip((int)Settings.GetValueByName(AnalyzerSettingsEnum.ExcludeAnalysis)).ToList(); //Move Average data List<Task> tasks = new List<Task>(); @@ -57,11 +60,12 @@ namespace Tango.DispenserAnalyzer.UI.Analyzers Task.WaitAll(tasks.ToArray()); //calculate difference Max Min values for each 300 values - int periodCalcMaxMin = 500; + int periodCalcMaxMin = (int)Settings.GetValueByName(AnalyzerSettingsEnum.MaxMinRange); + int intervalCalcMaxMin = (int)Settings.GetValueByName(AnalyzerSettingsEnum.MaxMinIntervals); List<int> differenceMaxMin = new List<int>(); List<int> differenceMaxMinToLocationArr = new List<int>(); int location_index = 0; - for (int i = 0; i < (filteredValues.Count - periodCalcMaxMin); i+= 300) + for (int i = 0; i < (filteredValues.Count - periodCalcMaxMin); i+= intervalCalcMaxMin) { var rangeItems =(filteredValues.Skip(i).Take(periodCalcMaxMin).ToList()); int range = (int)(rangeItems.Max(t => t.Pressure) - rangeItems.Min(t => t.Pressure)); @@ -71,7 +75,7 @@ namespace Tango.DispenserAnalyzer.UI.Analyzers } FlowAverageAnalyzerResult averageResult = new FlowAverageAnalyzerResult(); averageResult.AverageValue = filteredValues.Average(t => t.Pressure); - averageResult.Result = (averageResult.AverageValue <= 1850 && averageResult.AverageValue >= 1400) ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; + averageResult.Result = (averageResult.AverageValue <= Settings.GetValueByName(AnalyzerSettingsEnum.AvgMaxValue) && averageResult.AverageValue >= Settings.GetValueByName(AnalyzerSettingsEnum.AvgMinValue)) ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; results.Add(averageResult); FlowAnalyzerResult result = new FlowAnalyzerResult(++flowtestNumber); @@ -85,8 +89,8 @@ namespace Tango.DispenserAnalyzer.UI.Analyzers int avgMinIndex = rangeTestValues.Select(x => x.Index).Min(); int avgMaxIndex = rangeTestValues.Select(x => x.Index).Max(); double totalsec = TimeSpan.FromMilliseconds((avgMaxIndex - avgMinIndex) * 100).TotalSeconds; - result.Time = totalsec.ToString() + " sec (succeed for period < 4.5)"; ; - result.Result = (totalsec < 4.5) ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; + result.Time = totalsec.ToString() + $" sec (succeed for period < {AnalyzerSettingsEnum.FlowPBUPassFail})"; ; + result.Result = (totalsec < Settings.GetValueByName(AnalyzerSettingsEnum.FlowPBUPassFail)) ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; results.Add(result); } } @@ -155,12 +159,17 @@ namespace Tango.DispenserAnalyzer.UI.Analyzers } RangeToTimeChart.Title = $"Flow Time Location To Range {TestNumber}"; RangeToTimeChart.UpdateData(); + string filename = FileHelper.GetFileToSaveFlowRangeToTimeData(TestNumber); + if(filename.IsNotNullOrEmpty() && rangeToTimePoints.Count > 0) + { + ExportnDataToExcel(rangeToTimePoints.ToList(), filename); + } } private double BuildMeasurementError(List<int> range_values) { int count = range_values.Count(); - return (count - (count * 0.99)); + return (count - (int)Settings.GetValueByName(AnalyzerSettingsEnum.TakeOffMaxMin)); } /// <summary> @@ -187,11 +196,48 @@ namespace Tango.DispenserAnalyzer.UI.Analyzers break; } } - //Result = (range <= 25 && range >= 20) ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; + var res = range / AverageValue * 100; - Result = res <= 1.5 ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; + Result = res <= Settings.GetValueByName(AnalyzerSettingsEnum.MaxError) ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; return max_key; } + + /// <summary> + /// Exports the calibration data to excel. + /// </summary> + /// <param name="calibrationPoints">The calibration points.</param> + /// <param name="fileName">Name of the file.</param> + public static void ExportnDataToExcel(List<DataPoint> dataPoints, String fileName) + { + try + { + CreateDataExcelTemplate(fileName); + + using (ExcelWriter writer = new ExcelWriter(fileName)) + { + writer.WriteData(dataPoints, "RangeToTimeData"); + } + } + catch (Exception ex) + { + Debug.WriteLine("Error: ", ex.Message); + } + } + + /// <summary> + /// Creates the calibration data excel template. + /// </summary> + /// <param name="fileName">Name of the file.</param> + public static void CreateDataExcelTemplate(String fileName) + { + var stream = EmbeddedResourceHelper.GetEmbeddedResourceStream("Tango.DispenserAnalyzer.UI.Models.FlowRangeToTimeResults.xlsx"); + + using (FileStream fs = new FileStream(fileName, FileMode.Create)) + { + stream.Seek(0, SeekOrigin.Begin); + stream.CopyTo(fs); + } + } } public class MovingAverageFilter diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Analyzers/PressureBuildUpAnalyser.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Analyzers/PressureBuildUpAnalyser.cs index edc89f030..c4c5f6c65 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Analyzers/PressureBuildUpAnalyser.cs +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Analyzers/PressureBuildUpAnalyser.cs @@ -29,7 +29,7 @@ namespace Tango.DispenserAnalyzer.UI.Analyzers int avgMaxIndex = rangeTestValues.Select(x => x.Index).Max(); double totalsec = TimeSpan.FromMilliseconds((avgMaxIndex - avgMinIndex) * 100).TotalSeconds; result.Time = totalsec.ToString() + " sec"; - result.Result = (totalsec <= 12 && totalsec >= 7) ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; + result.Result = (totalsec < Settings.GetValueByName(AnalyzerSettingsEnum.PBUPassFail)) ? AnalyzerResultValue.Passed : AnalyzerResultValue.Failed; results.Add(result); } } diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/App.xaml b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/App.xaml index 73d8ea48c..8969f50af 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/App.xaml +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/App.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:local="clr-namespace:Tango.DispenserAnalyzer.UI" - StartupUri="MainWindow.xaml"> + Startup="Application_Startup"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/App.xaml.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/App.xaml.cs index 6250d17a1..c1876d806 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/App.xaml.cs +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/App.xaml.cs @@ -13,5 +13,12 @@ namespace Tango.DispenserAnalyzer.UI /// </summary> public partial class App : Application { + private void Application_Startup(object sender, StartupEventArgs e) + { + MainWindow wnd = new MainWindow(); + if (e.Args.Length >= 1) + wnd.SetOpenFileFromArgument(e.Args[0]); + wnd.Show(); + } } } diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/FileHelper.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/FileHelper.cs new file mode 100644 index 000000000..7172a4ff1 --- /dev/null +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/FileHelper.cs @@ -0,0 +1,44 @@ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.DispenserAnalyzer.UI +{ + public static class FileHelper + { + private const string FILE_EXTENSION = ".pdf"; + private const string FILE_EXEL_EXTENSION = ".xlsx"; + + public static string OpenFilePath{ get; set; } + + public static string GetResultFilePath() + { + if (File.Exists(OpenFilePath)) + { + var ext = Path.GetExtension(OpenFilePath); + var dir = Path.GetDirectoryName(OpenFilePath); + var resultFile = Path.Combine(dir, string.Format("{0}-result{1}", Path.GetFileNameWithoutExtension(OpenFilePath), FILE_EXTENSION)); + return resultFile; + } + return ""; + } + + public static string GetFileToSaveFlowRangeToTimeData( int extNumber) + { + if (File.Exists(OpenFilePath)) + { + var ext = Path.GetExtension(OpenFilePath); + var dir = Path.GetDirectoryName(OpenFilePath); + var resultFile = Path.Combine(dir, string.Format("{0}_rangeToTime{1}{2}", Path.GetFileNameWithoutExtension(OpenFilePath), extNumber.ToString(), FILE_EXEL_EXTENSION)); + return resultFile; + } + return ""; + } + + + } +} diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/MainWindow.xaml.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/MainWindow.xaml.cs index 9797d203b..43a573a7d 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/MainWindow.xaml.cs +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/MainWindow.xaml.cs @@ -48,6 +48,15 @@ namespace Tango.DispenserAnalyzer.UI ax.Maximum = ax.Minimum = Double.NaN; } + public void SetOpenFileFromArgument( string openFilePath) + { + if(_vm != null) + { + _vm.OpenFilePath = openFilePath; + _vm.Generate(); + } + } + private void TextBlock_PreviewDrop(object sender, DragEventArgs e) { string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Models/FlowRangeToTimeResults.xlsx b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Models/FlowRangeToTimeResults.xlsx Binary files differnew file mode 100644 index 000000000..5f0e4b651 --- /dev/null +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Models/FlowRangeToTimeResults.xlsx diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Models/SettingsModel.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Models/SettingsModel.cs index 0d9e20288..5540e4b25 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Models/SettingsModel.cs +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Models/SettingsModel.cs @@ -4,11 +4,24 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.Core; +using Tango.Core.Commands; namespace Tango.DispenserAnalyzer.UI.Models -{ - public class SettingsModel: ExtendedObject +{ + public interface ISettingsModel { + string PropertyName { get; set; } + double PropertyValue { get; set; } + double DefaultValue { get; set; } + string DefaultValueDisplay { get; set; } + double MinRangeValue { get; set; } + double MaxRangeValue { get; set; } + bool IsRangeVisible { get; set; } + } + + public class SettingsModel: ExtendedObject, ISettingsModel + { + public AnalyzerSettingsEnum _enumName; private string _propertyName; public string PropertyName @@ -22,7 +35,23 @@ namespace Tango.DispenserAnalyzer.UI.Models public double PropertyValue { get { return _propertyvalue; } - set { _propertyvalue = value; RaisePropertyChangedAuto(); } + set { + if( _propertyvalue != value) + { + _propertyvalue = value; + RaisePropertyChangedAuto(); + OnPropertyvalueChanged(); + } + } + } + + private void OnPropertyvalueChanged() + { + if(SettingValueEvent != null) + { + SettingValueEvent?.Invoke(this, new EventArgs()); + } + } private double _defaultValue; @@ -41,12 +70,78 @@ namespace Tango.DispenserAnalyzer.UI.Models set { _defaultValueDisplay = value; } } + private double _minDefaultRangeValue; + public double MinDefaultRangeValue + { + get { return _minDefaultRangeValue; } + set { _minDefaultRangeValue = value; RaisePropertyChangedAuto(); } + } + + private double _maxDefaultRangeValue; + public double MaxDefaultRangeValue + { + get { return _maxDefaultRangeValue; } + set { _maxDefaultRangeValue = value; RaisePropertyChangedAuto(); } + } + + private double _minRangeValue; + public double MinRangeValue + { + get { return _minRangeValue; } + set { + if (_minRangeValue != value) + { + _minRangeValue = value; + RaisePropertyChangedAuto(); + OnPropertyvalueChanged(); + } + } + } - public SettingsModel( string propertyName, string defaultValueDisplay, double defaultValue) + private double _maxRangeValue; + public double MaxRangeValue { - PropertyName = propertyName; + get { return _maxRangeValue; } + set { + if (_maxRangeValue != value) + { + _maxRangeValue = value; + RaisePropertyChangedAuto(); + OnPropertyvalueChanged(); + } + } + } + public bool IsRangeVisible { get; set; } + + public event EventHandler SettingValueEvent; + + public RelayCommand SetDefaultCommand { get; set; } + + + public SettingsModel(AnalyzerSettingsEnum enumName, string defaultValueDisplay, bool isrange = false) + { + _enumName = enumName; + PropertyName = _enumName.ToDescription(); DefaultValueDisplay = defaultValueDisplay; - DefaultValue = defaultValue; + DefaultValue = Settings.GetDefaultValueByName(enumName); + PropertyValue = Settings.GetValueByName(enumName); + IsRangeVisible = isrange; + MinDefaultRangeValue = IsRangeVisible ? Settings.GetDefaultValueByName(AnalyzerSettingsEnum.AvgMinValue) : 0.0; + MaxDefaultRangeValue = IsRangeVisible ? Settings.GetDefaultValueByName(AnalyzerSettingsEnum.AvgMaxValue) : 0.0; + MinRangeValue = IsRangeVisible? Settings.GetValueByName(AnalyzerSettingsEnum.AvgMinValue) : 0.0; + MaxRangeValue = IsRangeVisible? Settings.GetValueByName(AnalyzerSettingsEnum.AvgMaxValue) : 0.0; + SetDefaultCommand = new RelayCommand(SetDefault); + } + + private void SetDefault() + { + if(IsRangeVisible) + { + MinRangeValue = MinDefaultRangeValue; + MaxRangeValue = MaxDefaultRangeValue; + return; + } + PropertyValue = DefaultValue; } } } diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Settings.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Settings.cs new file mode 100644 index 000000000..9a1f10aed --- /dev/null +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Settings.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.DispenserAnalyzer.UI +{ + public enum AnalyzerSettingsEnum + { + //Undetermined + [Description("PBU Pass fail")] + PBUPassFail, + [Description("PBU Pass fail")] + FlowPBUPassFail, + [Description("Exclude from analysis")] + ExcludeAnalysis, + [Description("Avg value")] + AvgMaxValue, + [Description("Avg value")] + AvgMinValue, + [Description("Max-Min range")] + MaxMinRange, + [Description("Max Min intervals")] + MaxMinIntervals, + [Description("Max error")] + MaxError, + [Description("Take off 'Max-min' values(out of highest results)")] + TakeOffMaxMin, + + } + + public static class Settings + { + public static Dictionary<AnalyzerSettingsEnum, double> DefaultValues { get; set; } + public static Dictionary<AnalyzerSettingsEnum, double> CurrentValues { get; set; } + + static Settings() + { + DefaultValues = new Dictionary<AnalyzerSettingsEnum, double>(); + + DefaultValues[AnalyzerSettingsEnum.PBUPassFail] = 4.5; + DefaultValues[AnalyzerSettingsEnum.FlowPBUPassFail] = 4.5; + DefaultValues[AnalyzerSettingsEnum.ExcludeAnalysis] = 1800; + DefaultValues[AnalyzerSettingsEnum.AvgMinValue] = 1400; + DefaultValues[AnalyzerSettingsEnum.AvgMaxValue] = 1850; + DefaultValues[AnalyzerSettingsEnum.MaxMinRange] = 500; + DefaultValues[AnalyzerSettingsEnum.MaxMinIntervals] = 300; + DefaultValues[AnalyzerSettingsEnum.MaxError] = 1.5; + DefaultValues[AnalyzerSettingsEnum.TakeOffMaxMin] = 3; + + CurrentValues = new Dictionary<AnalyzerSettingsEnum, double>(); + CurrentValues[AnalyzerSettingsEnum.PBUPassFail] = 4.5; + CurrentValues[AnalyzerSettingsEnum.FlowPBUPassFail] = 4.5; + CurrentValues[AnalyzerSettingsEnum.ExcludeAnalysis] = 1800; + CurrentValues[AnalyzerSettingsEnum.AvgMinValue] = 1400; + CurrentValues[AnalyzerSettingsEnum.AvgMaxValue] = 1850; + CurrentValues[AnalyzerSettingsEnum.MaxMinRange] = 500; + CurrentValues[AnalyzerSettingsEnum.MaxMinIntervals] = 300; + CurrentValues[AnalyzerSettingsEnum.MaxError] = 1.5; + CurrentValues[AnalyzerSettingsEnum.TakeOffMaxMin] = 3; + } + public static double GetValueByName(AnalyzerSettingsEnum name) + { + double value; + if (CurrentValues.TryGetValue(name, out value)) + { + return value; + } + return 0.0; + } + public static void SetValueByName(AnalyzerSettingsEnum name, double value) + { + CurrentValues[name] = value; + } + public static double GetDefaultValueByName(AnalyzerSettingsEnum name) + { + double value; + if (DefaultValues.TryGetValue(name, out value)) + { + return value; + } + return 0.0; + } + } +} diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Tango.DispenserAnalyzer.UI.csproj b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Tango.DispenserAnalyzer.UI.csproj index 7efcaa58d..01a5a7122 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Tango.DispenserAnalyzer.UI.csproj +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/Tango.DispenserAnalyzer.UI.csproj @@ -29,8 +29,8 @@ <ProductName>Dispenser Analyser</ProductName> <PublisherName>Twine</PublisherName> <OpenBrowserOnPublish>false</OpenBrowserOnPublish> - <ApplicationRevision>4</ApplicationRevision> - <ApplicationVersion>1.2.1.%2a</ApplicationVersion> + <ApplicationRevision>2</ApplicationRevision> + <ApplicationVersion>2.1.1.%2a</ApplicationVersion> <UseApplicationTrust>true</UseApplicationTrust> <CreateDesktopShortcut>true</CreateDesktopShortcut> <PublishWizardCompleted>true</PublishWizardCompleted> @@ -140,10 +140,12 @@ <Compile Include="Analyzers\ReliabilityTestAnalyser.cs" /> <Compile Include="Analyzers\SealingAnalyzer.cs" /> <Compile Include="Analysis\AnalyzerAttribute.cs" /> + <Compile Include="FileHelper.cs" /> <Compile Include="Models\DispenserCsvRow.cs" /> <Compile Include="Models\DispenserSample.cs" /> <Compile Include="Models\DispenserSampleCommand.cs" /> <Compile Include="Models\SettingsModel.cs" /> + <Compile Include="Settings.cs" /> <Compile Include="ViewModels\MainWindowVM.cs" /> <Compile Include="ViewModels\SettingsVM.cs" /> <Compile Include="View\SettingsWnd.xaml.cs"> @@ -184,6 +186,7 @@ <Generator>ResXFileCodeGenerator</Generator> <LastGenOutput>Resources.Designer.cs</LastGenOutput> </EmbeddedResource> + <EmbeddedResource Include="Models\FlowRangeToTimeResults.xlsx" /> <None Include="packages.config" /> <None Include="Properties\Settings.settings"> <Generator>SettingsSingleFileGenerator</Generator> @@ -203,6 +206,10 @@ <Project>{58e8825f-0c96-449c-b320-1e82b0aa876b}</Project> <Name>Tango.CSV</Name> </ProjectReference> + <ProjectReference Include="..\..\Tango.Documents\Tango.Documents.csproj"> + <Project>{ca87a608-7b17-4c98-88f2-42abee10f4c1}</Project> + <Name>Tango.Documents</Name> + </ProjectReference> <ProjectReference Include="..\..\Tango.SharedUI\Tango.SharedUI.csproj"> <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project> <Name>Tango.SharedUI</Name> diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/View/SettingsWnd.xaml b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/View/SettingsWnd.xaml index 9d818a05b..2bfa2bba1 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/View/SettingsWnd.xaml +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/View/SettingsWnd.xaml @@ -6,7 +6,7 @@ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:local="clr-namespace:Tango.DispenserAnalyzer.UI.View" mc:Ignorable="d" - Title="Settings" Height="630" Width="800" FontSize="22" ResizeMode="NoResize" WindowStyle="ToolWindow"> + Title="Settings" Height="630" Width="800" FontSize="22" ResizeMode="NoResize" WindowStyle="ToolWindow" Closing="Window_Closing"> <Window.Resources> <Style TargetType="{x:Type TextBlock}" x:Key="WrapText"> <Setter Property="TextWrapping" Value="Wrap"/> @@ -71,11 +71,44 @@ <Setter Property="VerticalScrollBarVisibility" Value="Auto"/> </Style> - <DataGrid x:Key="PropertyDataGrid" HorizontalAlignment="Left" VerticalScrollBarVisibility ="Auto" SelectionUnit="FullRow" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" + <DataGrid x:Key="PropertyDataGrid" x:Shared="False" HorizontalAlignment="Left" VerticalScrollBarVisibility ="Auto" SelectionUnit="FullRow" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding .}" GridLinesVisibility="None" SelectionMode="Single" AlternatingRowBackground="#F6F6F6" FontSize="12" > <DataGrid.Columns> <DataGridTextColumn Header="Property Name" Binding="{Binding PropertyName}" Width="150" ElementStyle="{StaticResource WrapText}"/> - <DataGridTextColumn Header="Property Value" Binding="{Binding PropertyValue}" Width="150" IsReadOnly="False"></DataGridTextColumn> + <DataGridTemplateColumn Header="Property Value" Width="150"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <StackPanel Orientation="Horizontal"> + <TextBox Text="{Binding PropertyValue, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Width="50" VerticalAlignment="Top"> + <TextBox.Style> + <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource MaterialDesignTextBox}"> + <Setter Property="Visibility" Value="Visible"/> + <Style.Triggers> + <DataTrigger Binding="{Binding IsRangeVisible}" Value="true"> + <Setter Property="Visibility" Value="Collapsed"/> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + <DockPanel HorizontalAlignment="Stretch" Width="150"> + <DockPanel.Style> + <Style TargetType="{x:Type DockPanel}"> + <Setter Property="Visibility" Value="Collapsed"/> + <Style.Triggers> + <DataTrigger Binding="{Binding IsRangeVisible}" Value="true"> + <Setter Property="Visibility" Value="Visible"/> + </DataTrigger> + </Style.Triggers> + </Style> + </DockPanel.Style> + <TextBox DockPanel.Dock="Left" Name="MinRangeValue" Width="50" Text="{Binding MinRangeValue, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/> + <TextBox DockPanel.Dock="Right" Name="MaxRangeValue" Width="50" Text="{Binding MaxRangeValue, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/> + </DockPanel> + </StackPanel> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> <DataGridTextColumn Header="Default Value" Binding="{Binding DefaultValueDisplay}" Width="150" ElementStyle="{StaticResource WrapText}" /> <DataGridTemplateColumn Header="" Width="1*"> <DataGridTemplateColumn.CellStyle> @@ -104,13 +137,14 @@ <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid HorizontalAlignment="Stretch" VerticalAlignment="Center"> - <Button Width="80" Padding="2" Height="26" FontSize="12" Margin="0 8">Set Default</Button> + <Button Width="80" Padding="2" Height="26" FontSize="12" Margin="0 8" Command="{Binding SetDefaultCommand}">Set Default</Button> </Grid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> + </Window.Resources> @@ -124,27 +158,29 @@ </Grid.ColumnDefinitions> <Grid Grid.Row="0"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto"/> - <RowDefinition/> - </Grid.RowDefinitions> - <Grid Grid.Row="0" VerticalAlignment="Top"> - <Border Margin="20 20 20 0" BorderBrush="LightGray" BorderThickness="0.6" CornerRadius="4" Height="36"> - <Border.Effect> - <DropShadowEffect/> - </Border.Effect> - </Border> - <Border Margin="20 20 20 0" BorderBrush="LightGray" BorderThickness="0.6" CornerRadius="4" Height="34" Background="#C4EEFC"> - <TextBlock FontSize="22" Padding="2">Pressure build up test</TextBlock> - </Border> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + <Grid Grid.Row="0" VerticalAlignment="Top"> + <Border Margin="20 20 20 0" BorderBrush="LightGray" BorderThickness="0.6" CornerRadius="4" Height="36"> + <Border.Effect> + <DropShadowEffect/> + </Border.Effect> + </Border> + <Border Margin="20 20 20 0" BorderBrush="LightGray" BorderThickness="0.6" CornerRadius="4" Height="34" Background="#C4EEFC"> + <TextBlock FontSize="22" Padding="2">Pressure build up test</TextBlock> + </Border> + </Grid> + <ContentControl x:Name="PBUTestControl" Grid.Row="1" Content="{StaticResource PropertyDataGrid}" DataContext="{Binding Path=PBUTestSettings}" Margin="20 0 20 0"></ContentControl> </Grid> - <ContentControl Grid.Row="1" Margin="20 3 20 0" Content="{StaticResource PropertyDataGrid}" DataContext="{Binding Path=PBUTestSettings}"></ContentControl> </Grid> <Grid Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Stretch"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> - <RowDefinition Height="1*"/> + <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid Grid.Row="0" VerticalAlignment="Top"> <Border Margin="20 20 20 0" BorderBrush="LightGray" BorderThickness="0.6" CornerRadius="4" Height="36"> @@ -156,11 +192,11 @@ <TextBlock FontSize="22" Padding="2">Flow test</TextBlock> </Border> </Grid> - <ContentControl Grid.Row="1" Content="{StaticResource PropertyDataGrid}" DataContext="{Binding Path=FlowTestSettings}" Margin="20 0 20 0"></ContentControl> + <ContentControl x:Name="FlowTestControl" Grid.Row="1" Content="{StaticResource PropertyDataGrid}" DataContext="{Binding Path=FlowTestSettings}" Margin="20 0 20 0"></ContentControl> </Grid> </Grid> <Grid Grid.Row="2" > - <Button Width="80" HorizontalAlignment="Right" Margin="20">Save</Button> + <Button Width="80" HorizontalAlignment="Right" Margin="20" Click="SaveButton_Click" IsDefault="True">Save</Button> </Grid> </Grid> </Window> diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/View/SettingsWnd.xaml.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/View/SettingsWnd.xaml.cs index f0e35726e..9879d8f7a 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/View/SettingsWnd.xaml.cs +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/View/SettingsWnd.xaml.cs @@ -20,13 +20,20 @@ namespace Tango.DispenserAnalyzer.UI.View /// </summary> public partial class SettingsWnd : Window { + private SettingsVM vm; public SettingsWnd() { InitializeComponent(); - DataContext = new SettingsVM(); + vm = new SettingsVM(); + DataContext = vm; Loaded += Window_loaded; } + public Dictionary<AnalyzerSettingsEnum, double> GetChanges() + { + return vm.GetChanges(); + } + private void Window_loaded(object sender, RoutedEventArgs e) { Application curApp = Application.Current; @@ -34,5 +41,14 @@ namespace Tango.DispenserAnalyzer.UI.View this.Left = mainWindow.Left + (mainWindow.Width - this.ActualWidth) / 2; this.Top = mainWindow.Top + (mainWindow.Height - this.ActualHeight) / 2; } + + private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + vm.Dispose(); + } + public void SaveButton_Click(object sender, RoutedEventArgs e) + { + this.DialogResult = true; + } } } diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/ViewModels/MainWindowVM.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/ViewModels/MainWindowVM.cs index ab571ec43..70034b6e7 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/ViewModels/MainWindowVM.cs +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/ViewModels/MainWindowVM.cs @@ -161,16 +161,22 @@ namespace Tango.DispenserAnalyzer.UI.ViewModels _isRunning = false; this.Points = new List<DataPoint>(); - } #region Settings - + public void OpenSettingWnd() { SettingsWnd settings = new SettingsWnd(); settings.Owner = System.Windows.Application.Current.MainWindow; - settings.ShowDialog(); + if(true == settings.ShowDialog()) + { + Dictionary<AnalyzerSettingsEnum, double> changes = settings.GetChanges(); + foreach (KeyValuePair<AnalyzerSettingsEnum, double> entry in changes) + { + Settings.SetValueByName(entry.Key, entry.Value); + } + } } #endregion @@ -220,6 +226,7 @@ namespace Tango.DispenserAnalyzer.UI.ViewModels ResetSettings(); if(File.Exists(OpenFilePath)) { + FileHelper.OpenFilePath = OpenFilePath; FileName = Path.GetFileName(OpenFilePath); } } @@ -230,9 +237,9 @@ namespace Tango.DispenserAnalyzer.UI.ViewModels { return (OpenFilePath!= null && OpenFilePath.Length != 0 && File.Exists(OpenFilePath)); } - private async void Generate() + public async void Generate() { - if (IsFileLocked(OpenFilePath)) + if (false == File.Exists(OpenFilePath) || IsFileLocked(OpenFilePath) ) return; ResetSettings(); @@ -328,13 +335,9 @@ namespace Tango.DispenserAnalyzer.UI.ViewModels await Task.Delay(200); try { - if (File.Exists(OpenFilePath)) + var resultFile = FileHelper.GetResultFilePath(); + if (resultFile.IsNotNullOrEmpty()) { - var fileName = Path.GetFileNameWithoutExtension(OpenFilePath); - fileName += "_result"; - var ext = Path.GetExtension(OpenFilePath); - var dir = Path.GetDirectoryName(OpenFilePath); - var resultFile = Path.Combine(dir, string.Format("{0}-result{1}", Path.GetFileNameWithoutExtension(OpenFilePath), FILE_EXTENSION)); SaveResultsAsXps(resultFile); } } @@ -359,6 +362,8 @@ namespace Tango.DispenserAnalyzer.UI.ViewModels int index = 0; foreach (var item in all_plots) { + var seriesdata = item.Series[0].ItemsSource; + item.RaiseEvent(new System.Windows.RoutedEventArgs(OxyPlot.Wpf.PlotView.LoadedEvent)); item.InvalidatePlot(true); if (item.IsMeasureValid && item.ActualHeight > 0) diff --git a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/ViewModels/SettingsVM.cs b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/ViewModels/SettingsVM.cs index 99b6e948a..d5c54ab08 100644 --- a/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/ViewModels/SettingsVM.cs +++ b/Software/Visual_Studio/Utilities/Tango.DispenserAnalyzer.UI/ViewModels/SettingsVM.cs @@ -9,7 +9,7 @@ using Tango.SharedUI; namespace Tango.DispenserAnalyzer.UI.ViewModels { - public class SettingsVM : ViewModel + public class SettingsVM : ViewModel, IDisposable { private ObservableCollection<SettingsModel> _PBUSettings; @@ -27,28 +27,61 @@ namespace Tango.DispenserAnalyzer.UI.ViewModels set { _flowTestSettings = value; RaisePropertyChangedAuto(); } } + private Dictionary<AnalyzerSettingsEnum, double> changedValues; + public SettingsVM() { _PBUSettings = new ObservableCollection<SettingsModel>(); InitPBUTestSettings(); _flowTestSettings = new ObservableCollection<SettingsModel>(); + changedValues = new Dictionary<AnalyzerSettingsEnum, double>(); InitFlowTestSettings(); } private void InitPBUTestSettings() { - _PBUSettings.Add(new SettingsModel("PBU Pass fail", "4.5 sec", 4.5)); + var setting = new SettingsModel(AnalyzerSettingsEnum.PBUPassFail, "4.5 sec"); + setting.SettingValueEvent += new EventHandler(OnSettingValueChanged); + _PBUSettings.Add(setting); } private void InitFlowTestSettings() { - _flowTestSettings.Add(new SettingsModel("PBU Pass fail", "4.5 sec", 4.5)); - _flowTestSettings.Add(new SettingsModel("Exclude from analysis", "1800 reads", 1800)); - _flowTestSettings.Add(new SettingsModel("Avg value", "1400-1850 [mbar]", 1400)); - _flowTestSettings.Add(new SettingsModel("Max-Min range", "500 reads", 500)); - _flowTestSettings.Add(new SettingsModel("Max Min intervals", "300 reads", 300)); - _flowTestSettings.Add(new SettingsModel("Max error", "1.5%", 1.5)); - _flowTestSettings.Add(new SettingsModel("Take off 'Max-min' values (out of highest results)", "3", 3)); + _flowTestSettings.Add(new SettingsModel(AnalyzerSettingsEnum.FlowPBUPassFail, "4.5 sec")); + _flowTestSettings.Add(new SettingsModel(AnalyzerSettingsEnum.ExcludeAnalysis, "1800 reads")); + _flowTestSettings.Add(new SettingsModel(AnalyzerSettingsEnum.AvgMinValue, "1400-1850 [mbar]", true)); + _flowTestSettings.Add(new SettingsModel(AnalyzerSettingsEnum.MaxMinRange, "500 reads")); + _flowTestSettings.Add(new SettingsModel(AnalyzerSettingsEnum.MaxMinIntervals, "300 reads")); + _flowTestSettings.Add(new SettingsModel(AnalyzerSettingsEnum.MaxError, "1.5%")); + _flowTestSettings.Add(new SettingsModel(AnalyzerSettingsEnum.TakeOffMaxMin, "3")); + + _flowTestSettings.ToList().ForEach(x => x.SettingValueEvent += new EventHandler(OnSettingValueChanged)); + } + + private void OnSettingValueChanged(object sender, EventArgs e) + { + if(sender is SettingsModel) + { + SettingsModel settingModel = sender as SettingsModel; + if(settingModel.IsRangeVisible) + { + changedValues[AnalyzerSettingsEnum.AvgMinValue] = settingModel.MinRangeValue; + changedValues[AnalyzerSettingsEnum.AvgMaxValue] = settingModel.MaxRangeValue; + } + else + changedValues[settingModel._enumName] = settingModel.PropertyValue; + } + } + + public Dictionary<AnalyzerSettingsEnum, double> GetChanges() + { + return changedValues; + } + + public void Dispose() + { + _PBUSettings.ToList().ForEach(x => x.SettingValueEvent -= OnSettingValueChanged); + _flowTestSettings.ToList().ForEach(x => x.SettingValueEvent -= OnSettingValueChanged); } } } |
