}//end:DecreaseRun /// <summary> /// Finds the run with the least remains for given ets /// by trying every run from ets.MaxRun to 0. /// </summary> /// <param name="ets">Ets count cannot be > ETS_ON_SHEET</param> /// <returns></returns> protected static OutStats FindBestRun(Zakaz ets) { if (ets.Count > Constants.ETS_ON_SHEET) { throw new ArgumentException("FindBestRun cannot operate with so many ets."); } int currentRun = ets.MaxRun; OutStats bestResult = GetStatsForRun(ets, currentRun); //Initialize bestResult if (!bestResult.IsValid) { throw new Exception("FindBestRun: Invalid stats obtained for MaxRun. Internal logic error."); } const int STEP = 100; currentRun -= STEP; while (currentRun > 0) { OutStats result = GetStatsForRun(ets, currentRun); if (result.IsValid && result < bestResult) { bestResult = result; } currentRun -= STEP; } return(bestResult); }//end:FindBestRun
}//end:IsGcd /// <summary> /// Calculates statistics for given set of ets, /// which would be printed with given run /// </summary> protected static OutStats GetStatsForRun(Zakaz ets, int run) { OutStats result = new OutStats(); result.Run = run; foreach (Etyketka et in ets) { Etyketka tmpEt = new Etyketka(et); if (et.Run > run) { tmpEt.CountOnSheet = et.Run / run; //ex. 7/3=2 int remainder = et.Run % run; //Get the remainder if (remainder > 0) // "Round up" if there is some remainer { tmpEt.Overprint = run - remainder; tmpEt.CountOnSheet++; } } else { tmpEt.CountOnSheet = 1; tmpEt.Overprint = run - et.Run; } if (tmpEt.Overprint < 0) { throw new ArithmeticException("GetStatsForRun: something is wrong, negative Overprints detected!"); } result.Ets.Add(tmpEt); result.EtsOnSheetCount += tmpEt.CountOnSheet; result.OverprintsSum += tmpEt.Overprint; } //foreach return(result); } //end:GetEtsOnSheetForRun
}//end:SplitFromMinToMax /// <summary> /// Determines minimum run for given Zakaz, /// which produces valid OutStats /// </summary> /// <param name="ets">Given zakaz remains immutable</param> /// <returns>Minimum valid run</returns> protected static int GetMinValidRun(Zakaz ets) { // Obtain stats for minimum run int run = ets.MinRun; OutStats tmpStats = GetStatsForRun(ets, run); while (!tmpStats.IsValid) { run += 100; //Increase the run and the EtsOnSheetCount being decreased tmpStats = GetStatsForRun(ets, run); } return(run); }//end:GetMinValidRun
} //end:GetEtsOnSheetForRun /// <summary> /// Tries to decrease given run to maximize the fill of the sheet with given ets /// </summary> protected static OutStats DecreaseRun(Zakaz ets, int run) { //Get the etsOnSheetSum for the run OutStats result = GetStatsForRun(ets, run); if (!result.IsValid) { throw new ArithmeticException("DecreaseRun: EtsOnSheetCount sum bigger than ETS_ON_SHEET. That is nonesense!"); } if (result.EtsOnSheetCount == Constants.ETS_ON_SHEET) { return(result); } //Try to increase the run for every single et and choose the best result OutStats tmpStats = null; int etCount; foreach (Etyketka et in ets) { etCount = et.CountOnSheet; do { etCount += 1; //Fit the run so, that etsOnSheet count for the et increased by 1 //and get the stats for the newRun tmpStats = GetStatsForRun(ets, et.Run / etCount); //Choose the best result if (tmpStats.IsValid && tmpStats < result) { result = tmpStats; } } while (tmpStats.IsValid); }//foreach //If something went wrong and all ets have some greater-than-zero overprint, fix that int resultMinOverprint = (from e in result.Ets select e.Overprint).Min(); if (resultMinOverprint > 0) { return(GetStatsForRun(result.Ets, result.Run - resultMinOverprint)); } else { return(result); } }//end:DecreaseRun
}//end:FindBestRun ///<summary> ///Splits provided list of ets and applies FirstPass on each sublist. ///Collects OutStats from each FirstPass and returns them as single list. ///</summary> protected static StatsList SplitFromMinToMax(Zakaz ets) { //Make given ets immutable Zakaz _ets = new Zakaz(ets); //Order ets by runs _ets.Sort(new CompareEtsByRunMinToMax()); int runIncrement = 0; StatsList TheBestResult = null; Zakaz zakazForMinRun = null; OutStats statsForMinRun = null; do { //Split ets to groups with the sum count on the sheet <= Constants.ETS_ON_SHEET //and build temporary stats list statsForMinRun = GetStatsForRun(_ets, _ets.MinRun + runIncrement); //For now statsForMinRun are not valid, but we don't bother, //because we would split ets later zakazForMinRun = statsForMinRun.Ets; StatsList tmpResult = new StatsList(); Zakaz part1; Zakaz part2; do { part1 = new Zakaz(); part2 = new Zakaz(); int count = 0; foreach (Etyketka et in zakazForMinRun) { if (count + et.CountOnSheet <= Constants.ETS_ON_SHEET) { //Select first ets group that fits at one sheet part1.Add(et); } else { //Add all other ets to the second group part2.Add(et); } count += et.CountOnSheet; }//foreach //Part1 is valid, as far as previous if-expression is true OutStats os = GetStatsForRun(part1, part1.MinRun + runIncrement); if (!os.IsValid) { if (TheBestResult != null) { return(TheBestResult); } else { throw new Exception("Invalid Algorithm!"); } } tmpResult.Add(os); //For second group recalculating stats with its MinRun if (part2.Count > 0) { statsForMinRun = GetStatsForRun(part2, part2.MinRun + runIncrement); //For now statsForMinRun are not valid, but we don't bother, //because we would split part2 in the next loop zakazForMinRun = statsForMinRun.Ets; } } while (part2.Count > 0); //Select the best result as the final result returned if (TheBestResult == null) { TheBestResult = tmpResult; } if (TheBestResult > tmpResult) { TheBestResult = tmpResult; } runIncrement += 100; } while (_ets.MinRun + runIncrement <= _ets.MaxRun); return(TheBestResult); }//end:SplitFromMinToMax