/// <summary> /// Стандартное клонирование объекта /// </summary> /// <returns></returns> public new object Clone() { TaskList NewList = new TaskList(); foreach (TaskItem item in items) { NewList.Add((TaskItem)item.Clone()); } return NewList; }
public InsertTask(ScheduleManager SchedMan) { InitializeComponent(); sm = SchedMan; // копируем задания, чтоб можно было нажать отмена TempTasks = (TaskList)sm.Data.Tasks.Clone(); LoadProduction(); LoadMaterial(); LoadOrders(); Text = "Добавить задание"; }
/// <summary> /// Расставляем директивные сроки в зависмости от заказа /// </summary> /// <param name="Orders">Списко исходных заказов.</param> /// <param name="Tasks">Список исходных заданий.</param> private void SetDirectiveFromOrder(OrderList Orders, TaskList Tasks) { // Копируем директивные сроки из заказа в каждое задание for (int i = 0; i < Orders.Count; i++) { for (int j = 0; j < Tasks.Count; j++) { if (Tasks[j].OrderId == Orders[i].Id) { if (Orders[i].DeadLine != null) { Tasks[j].UseDeadLine = true; Tasks[j].DeadLine = Orders[i].DeadLine.Value; } else Tasks[j].UseDeadLine = false; } } } }
/// <summary> /// Возвращает идентификатор наиболее важного задания. /// Важность зависит от времени выполнения. /// Чем дольше задание выполняется, тем оно важнее. /// </summary> /// <param name="DefaultList"></param> /// <param name="MaterialID"></param> /// <returns></returns> private int MostImportantTask(TaskList Tasks, MaterialList Materials, ProductionList Productions, int MaterialID, BaseDeviceType DeviceType) { int ResultId = -1; if (Tasks.Count == 0) return ResultId; // находим индекс первого задания данного типа int ResultIndex = -1; for (int i = 0; i < Tasks.Count; i++) { if (Tasks[i].MaterialId == MaterialID) { ResultIndex = i; break; } } // если заданий под нужный материал вовсе нет, то до свидания if (ResultIndex == -1) return ResultId; ResultId = Tasks[ResultIndex].Id; for (int i = ResultIndex + 1; i < Tasks.Count; i++) { if (Tasks[i].MaterialId != MaterialID) continue; if ((DeviceType == BaseDeviceType.Saw ? Tasks[i].SawingTime(Materials, Productions) : Tasks[i].PolishingTime(Materials, Productions)) > (DeviceType == BaseDeviceType.Saw ? Tasks[ResultIndex].SawingTime(Materials, Productions) : Tasks[ResultIndex].PolishingTime(Materials, Productions))) { ResultId = Tasks[i].Id; ResultIndex = i; } } return ResultId; }
/// <summary> /// Метод возвращает идентификатор материала которого больше всего /// по времени обработки на пиле. /// </summary> /// <param name="DefaultSawingList"></param> private int MostImportantMaterial(TaskList Tasks, MaterialList Materials, ProductionList Productions, BaseDeviceType DeviceType) { // список в котором хранится материал и суммарное время всех заданий // под данный материал List<MaterialPair> material = new List<MaterialPair>(); // перебираем задания и наполняем список времен for (int i = 0; i < Tasks.Count; i++) { int CurrentMaterialID = Tasks[i].MaterialId; int FindedMaterialIndex = -1; for (int j = 0; j < material.Count; j++) { if (material[j].ID == CurrentMaterialID) { FindedMaterialIndex = j; break; } } // если материал уже есть в списке if (FindedMaterialIndex > -1) material[FindedMaterialIndex].Time += DeviceType == BaseDeviceType.Saw ? Tasks[i].SawingTime(Materials, Productions) : Tasks[i].PolishingTime(Materials, Productions); else // если материала нет в списке material.Add(new MaterialPair(CurrentMaterialID, DeviceType == BaseDeviceType.Saw ? Tasks[i].SawingTime(Materials, Productions) : Tasks[i].PolishingTime(Materials, Productions))); } // перебираем задания и наполняем список времен int Result = -1; double CurrentMaxTime = 0; for (int i = 0; i < material.Count; i++) { if (material[i].Time > CurrentMaxTime) { CurrentMaxTime = material[i].Time; Result = i; } } return Result != -1 ? material[Result].ID : -1; }
/// <summary> /// Рассчитать расписание. /// </summary> public void StartSchedule() { // устанавливаем в каждое задание директивный срок SetDirectiveFromOrder(data.Orders, data.Tasks); // Сбрасываем предыдущее расписание data.Saws.ClearCompleteTasks(); data.Grinders.ClearCompleteTasks(); // устанавливаем текущее время double T = 0; // формируем список исходных заданий для распиливания TaskList DefaultSawingList = new TaskList(); for (int i = 0; i < data.Tasks.Count; i++) { if (data.Tasks[i].SawingTime(data.Materials, data.Productions) != 0) { DefaultSawingList.AddCopy((TaskItem)data.Tasks[i].Clone()); } } // формируем список исходных заданий для шлифования из заданий не требующих распиливания TaskList DefaultPolishingList = new TaskList(); for (int i = 0; i < data.Tasks.Count; i++) { if (data.Tasks[i].SawingTime(data.Materials, data.Productions) == 0 && data.Tasks[i].PolishingTime(data.Materials, data.Productions) != 0) { DefaultPolishingList.AddCopy((TaskItem)data.Tasks[i].Clone()); } } // // первая настройка пил // // сортируем пилы по возрастанию кол-ва поддерживаемых материалов for (int i = 0, i_end = data.Saws.Count - 1; i < i_end; i++) { for (int j = i + 1, j_end = data.Saws.Count; j < j_end; j++) { if (data.Saws[i].SupportedMaterials.Count > data.Saws[j].SupportedMaterials.Count) { TimeDevice tmp = data.Saws[i]; data.Saws[i] = data.Saws[j]; data.Saws[j] = tmp; } } } bool BigTaskFirst = data.Saws.Count < data.Grinders.Count; do { data.Saws.Service(T); // назначаем каждому устройству задание for (int i = 0, i_end = data.Saws.Count; i < i_end; i++) { if (!data.Saws[i].IsBusy()) // если устройство не занято { int TaskId = data.Saws[i].MostImpTask(DefaultSawingList, data.Materials, data.Productions, BaseDeviceType.Saw, BigTaskFirst); if (TaskId != -1) { int TaskIndex = DefaultSawingList.GetIndexById(TaskId); int ProdIndex = data.Productions.GetIndexById(DefaultSawingList[TaskIndex].ProductionId); data.Saws[i].AddTask(TaskId, DefaultSawingList[TaskIndex].MaterialId, T, DefaultSawingList[TaskIndex].SawingTime(data.Materials, data.Productions)); DefaultSawingList.DeleteById(TaskId); } } } data.Grinders.Service(T); // назначаем каждому станку for (int i = 0, i_end = data.Grinders.Count; i < i_end; i++) { if (!data.Grinders[i].IsBusy()) // если устройство не занято { // получаем идентификатор задания с учётом того как настроено устройство int FirstTaskId = data.Grinders[i].MostImpTask(DefaultPolishingList, data.Materials, data.Productions, BaseDeviceType.Grinder, BigTaskFirst); // альтернативное задание int SecondTaskId = data.Grinders[i].ImpTask(DefaultPolishingList, data.Materials, data.Productions, BaseDeviceType.Grinder); if (FirstTaskId != SecondTaskId && SecondTaskId != -1) { int FirstTaskIndex = DefaultPolishingList.GetIndexById(FirstTaskId); int FirstMaterialId = DefaultPolishingList[FirstTaskIndex].MaterialId; // есть ли устройство - альтернатива текущему? int AlternateDeviceId = data.Grinders.GetBestAlternative(FirstMaterialId, data.Grinders[i].Id, BaseDeviceType.Grinder); if (AlternateDeviceId != -1) // альтернатива существует { int AlternateDeviceIndex = data.Grinders.GetIndexById(AlternateDeviceId); int SecondTaskIndex = DefaultPolishingList.GetIndexById(SecondTaskId); int SecondMaterialId = DefaultPolishingList[SecondTaskIndex].MaterialId; int FirstProductIndex = data.Productions.GetIndexById(DefaultPolishingList[SecondTaskIndex].ProductionId); // время обработки первого задания + конфигурация первого станка под второй материал double FirstTime = DefaultPolishingList[FirstTaskIndex].PolishingTime(data.Materials, data.Productions) + data.Grinders[i].GetConfigTime(SecondMaterialId); // время до конца отработки альтернативного устройства + время обработки первого задания + конфигурация второго станка под второй материал double SecondTime = data.Grinders[AlternateDeviceIndex].Time + DefaultPolishingList.TaskDurationByMaterial(FirstMaterialId, data.Materials, data.Productions, BaseDeviceType.Grinder); if (data.Grinders[AlternateDeviceIndex].CurrentMaterialId != FirstMaterialId) SecondTime += data.Grinders[AlternateDeviceIndex].GetConfigTime(FirstMaterialId); if (SecondTime <= FirstTime) { FirstTaskId = SecondTaskId; } } } if (FirstTaskId != -1) { int TaskIndex = DefaultPolishingList.GetIndexById(FirstTaskId); int ProdIndex = data.Productions.GetIndexById(DefaultPolishingList[TaskIndex].ProductionId); data.Grinders[i].AddTask(FirstTaskId, DefaultPolishingList[TaskIndex].MaterialId, T, DefaultPolishingList[TaskIndex].PolishingTime(data.Materials, data.Productions)); DefaultPolishingList.DeleteById(FirstTaskId); } } } //Определяем шаг по времени double Step = GetStep(data.Saws, data.Grinders); // совершаем временной шаг для пил for (int i = 0; i < data.Saws.Count; i++) { int CompleteTaskId = data.Saws[i].MakeStep(Step); // если завершилось распиливание if (CompleteTaskId >= 0) { // получаем задание, которое прошло распиливание int TaskIndex = data.Tasks.GetIndexById(CompleteTaskId); // если завершенное задание требует шлифования, отправляем его в очередь на шлифовку if (data.Tasks[TaskIndex].PolishingTime(data.Materials, data.Productions) != 0) { TaskItem TaskCopy = (TaskItem)data.Tasks[TaskIndex].Clone(); TaskCopy.TimeOfLastUsing = T; DefaultPolishingList.AddCopy(TaskCopy); } } } // совершаем временной шаг шлифовщиков for (int i = 0; i < data.Grinders.Count; i++) { int CompleteTaskId = data.Grinders[i].MakeStep(Step); } // изменяем текущее время T += Step; } while (data.Saws.OneWorkDeviceExist() || data.Grinders.OneWorkDeviceExist() || DefaultSawingList.Count != 0 || DefaultPolishingList.Count != 0); }
/// <summary> /// Возвращает наиболее просроченное задание /// </summary> /// <param name="DefaultList">Список заданий.</param> /// <param name="CurrentTime">Текущее время.</param> /// <returns>Идентификатор просроченного задания или -1, если такого задания нет.</returns> private int GetOverdueTask(TaskList DefaultList, double CurrentTime) { DateTime dtCurrentTime = data.BaseTime.AddMinutes(CurrentTime); int ResultIndex = -1; DateTime MostOverdueDate = new DateTime(); for (int i = 0; i < DefaultList.Count; i++) { if (DefaultList[i].UseDeadLine) { if (DefaultList[i].DeadLine < dtCurrentTime) // если задание просрочено { if (ResultIndex == -1) { MostOverdueDate = DefaultList[i].DeadLine; ResultIndex = i; } else { if (MostOverdueDate > DefaultList[i].DeadLine) { ResultIndex = i; } } } } } return ResultIndex != -1 ? DefaultList[ResultIndex].Id : -1; }
/// <summary> /// Возвращает индекс задания в коллекции с наибольшим временем распиливания. /// </summary> /// <param name="list">Коллекция заданий в которой производится поиск.</param> /// <returns>Индекс задания.</returns> protected int GetTaskIndexWithMostLongSawing(TaskList list) { if (list.Count == 0) return -1; int Result = 0; for (int i = 1; i < list.Count; i++) { if (list[i].SawingTime(data.Materials, data.Productions) > list[Result].SawingTime(data.Materials, data.Productions)) Result = 0; } return Result; }
/// <summary> /// Рассчитать расписание. /// </summary> public void StartSchedule2() { // устанавливаем в каждое задание директивный срок SetDirectiveFromOrder(data.Orders, data.Tasks); // Сбрасываем предыдущее расписание data.Saws.ClearCompleteTasks(); data.Grinders.ClearCompleteTasks(); // устанавливаем текущее время double T = 0; // формируем список исходных заданий для распиливания TaskList DefaultSawingList = new TaskList(); for (int i = 0; i < data.Tasks.Count; i++) { if (data.Tasks[i].SawingTime(data.Materials, data.Productions) != 0) { DefaultSawingList.AddCopy((TaskItem)data.Tasks[i].Clone()); } } // формируем список исходных заданий для шлифования из заданий не требующих распиливания TaskList DefaultPolishingList = new TaskList(); for (int i = 0; i < data.Tasks.Count; i++) { if (data.Tasks[i].SawingTime(data.Materials, data.Productions) == 0 && data.Tasks[i].PolishingTime(data.Materials, data.Productions) != 0) { DefaultPolishingList.AddCopy((TaskItem)data.Tasks[i].Clone()); } } // // первая настройка пил // // сортируем пилы по возрастанию кол-ва поддерживаемых материалов for (int i = 0, i_end = data.Saws.Count - 1; i < i_end; i++) { for (int j = i + 1, j_end = data.Saws.Count; j < j_end; j++) { if (data.Saws[i].SupportedMaterials.Count > data.Saws[j].SupportedMaterials.Count) { TimeDevice tmp = data.Saws[i]; data.Saws[i] = data.Saws[j]; data.Saws[j] = tmp; } } } do { data.Saws.Service(T); // назначаем каждому устройству задание for (int i = 0, i_end = data.Saws.Count; i < i_end; i++) { if (!data.Saws[i].IsBusy()) // если устройство не занято { int TaskId = data.Saws[i].MostImpTask2(DefaultSawingList, data.Materials, data.Productions, BaseDeviceType.Saw); if (TaskId != -1) { // получаем время до истечения директивногог срока int TaskIndex = DefaultSawingList.GetIndexById(TaskId); if (DefaultSawingList[TaskIndex].UseDeadLine) { // время через которое наступит deadline для задания double TimeToExpare = (DefaultSawingList[TaskIndex].DeadLine - data.BaseTime.AddMinutes(T)).TotalMinutes; if (TimeToExpare > 0) // если время ещё есть { // рассмотрим, уложиться ли задание в директивный срок // в худшем случае относительно настройки и в лучшем случае относительно // свободности станков double RealWorkTime = DefaultSawingList[TaskIndex].SawingTime(data.Materials, data.Productions) + DefaultSawingList[TaskIndex].PolishingTime(data.Materials, data.Productions) + data.Saws.GetMidConfigTime(DefaultSawingList[TaskIndex].MaterialId) + data.Grinders.GetMidConfigTime(DefaultSawingList[TaskIndex].MaterialId); // теперь определяем есть ли время, до которого необходимо вкрай начать выполнять это задание double DeltaTime = TimeToExpare - RealWorkTime; /* // определим примерное суммарное время заданий, которое нужно выполнить до этого же срока или ранее // примерное, потому что не учитываем настройку double TaskDurationSum = DefaultSawingList.GetTaskDurationByDeadLine(DefaultSawingList[TaskIndex].DeadLine, data.Materials, data.Productions); // получим количество таких заданий. // и представим что хотя бы для 20% заданий потребуется настройка int TaskCountByDeadLine = DefaultSawingList.GetTaskCountByDeadLine(DefaultSawingList[TaskIndex].DeadLine); // учтем время примерной настройки TaskDurationSum += 0.2 * TaskCountByDeadLine * (data.Saws.GetMidConfigTime(data.Materials) + data.Grinders.GetMidConfigTime(data.Materials)); // получим новую дельту DeltaTime -= TaskDurationSum; */ if (DeltaTime > 0) { // а теперь попробуем найти задание int AlterTaskId = data.Saws[i].MostImpTaskWithTimeLimit(DefaultSawingList, data.Materials, data.Productions, BaseDeviceType.Saw, data.Grinders, DeltaTime); if (AlterTaskId != -1) // если задание нашлось, то выполняем его { TaskId = AlterTaskId; TaskIndex = DefaultSawingList.GetIndexById(TaskId); } } } } int ProdIndex = data.Productions.GetIndexById(DefaultSawingList[TaskIndex].ProductionId); data.Saws[i].AddTask(TaskId, DefaultSawingList[TaskIndex].MaterialId, T, DefaultSawingList[TaskIndex].SawingTime(data.Materials, data.Productions)); DefaultSawingList.DeleteById(TaskId); } } } data.Grinders.Service(T); // назначаем каждому станку for (int i = 0, i_end = data.Grinders.Count; i < i_end; i++) { if (!data.Grinders[i].IsBusy()) // если устройство не занято { /* // получаем самое застарелое задание в очереди int TaskId = data.Grinders[i].GetOldestTask(DefaultPolishingList); if (TaskId != -1) { int TaskIndex = DefaultPolishingList.GetIndexById(TaskId); int ProdIndex = data.Productions.GetIndexById(DefaultPolishingList[TaskIndex].ProductionId); data.Grinders[i].AddTask(TaskId, DefaultPolishingList[TaskIndex].MaterialId, T, DefaultPolishingList[TaskIndex].SawingTime(data.Materials, data.Productions)); DefaultPolishingList.DeleteById(TaskId); } */ int TaskId = data.Grinders[i].MostImpTask2(DefaultPolishingList, data.Materials, data.Productions, BaseDeviceType.Grinder); if (TaskId != -1) { int TaskIndex = DefaultPolishingList.GetIndexById(TaskId); int ProdIndex = data.Productions.GetIndexById(DefaultPolishingList[TaskIndex].ProductionId); data.Grinders[i].AddTask(TaskId, DefaultPolishingList[TaskIndex].MaterialId, T, DefaultPolishingList[TaskIndex].SawingTime(data.Materials, data.Productions)); DefaultPolishingList.DeleteById(TaskId); } } } //Определяем шаг по времени double Step = GetStep(data.Saws, data.Grinders); // совершаем временной шаг для пил for (int i = 0; i < data.Saws.Count; i++) { int CompleteTaskId = data.Saws[i].MakeStep(Step); // если завершилось распиливание if (CompleteTaskId >= 0) { // получаем задание, которое прошло распиливание int TaskIndex = data.Tasks.GetIndexById(CompleteTaskId); // если завершенное задание требует шлифования, отправляем его в очередь на шлифовку if (data.Tasks[TaskIndex].PolishingTime(data.Materials, data.Productions) != 0) { TaskItem TaskCopy = (TaskItem)data.Tasks[TaskIndex].Clone(); TaskCopy.TimeOfLastUsing = T; DefaultPolishingList.AddCopy(TaskCopy); } } } // совершаем временной шаг шлифовщиков for (int i = 0; i < data.Grinders.Count; i++) { int CompleteTaskId = data.Grinders[i].MakeStep(Step); } // изменяем текущее время T += Step; } while (data.Saws.OneWorkDeviceExist() || data.Grinders.OneWorkDeviceExist() || DefaultSawingList.Count != 0 || DefaultPolishingList.Count != 0); }
/// <summary> /// Возвращает самое простаивающее устройство с учётом /// материала, который содержится в Tasks /// </summary> /// <param name="Tasks"></param> /// <returns></returns> public int GetNotBusyDeviceId(TaskList Tasks) { int BestIndex = -1; for (int i = 0, i_end = this.Count; i < i_end; i++) { if (!this[i].IsBusy()) { if (BestIndex == -1) { for (int j = 0; j < Tasks.Count; j++) { if (this[i].IsSupportMaterial(Tasks[j].MaterialId)) { // если это устройство свободно и поддерживает хотя бы один материал из списка BestIndex = i; break; } } } else { if (this[i].LastUsed < this[BestIndex].LastUsed) { for (int j = 0; j < Tasks.Count; j++) { if (this[i].IsSupportMaterial(Tasks[j].MaterialId)) { // если это устройство свободно и поддерживает хотя бы один материал из списка BestIndex = i; break; } } } } } } return BestIndex != -1 ? this[BestIndex].Id : -1; }
/// <summary> /// Определяет, есть ли сободные ненастроенные устройства /// способные принять хотя бы одно из заданий. /// </summary> /// <returns></returns> public bool FreeUnconfiguredDeviceExist(TaskList Tasks) { for (int i = 0; i < items.Count; i++) { // если пила не занята и не настроена if (!((TimeDevice)items[i]).IsBusy() && ((TimeDevice)items[i]).CurrentMaterialId == -1) { for (int j = 0; j < Tasks.Count; j++) { if (((TimeDevice)items[i]).IsSupportMaterial(Tasks[j].MaterialId)) return true; } } } return false; }
public void Assign(Configuration Obj) { baseTime = Obj.baseTime; materials = (MaterialList)Obj.materials.Clone(); saws = (DeviceList)Obj.saws.Clone(); grinders = (DeviceList)Obj.grinders.Clone(); productions = (ProductionList)Obj.productions.Clone(); customers = (CustomerList)Obj.customers.Clone(); orders = (OrderList)Obj.orders.Clone(); tasks = (TaskList)Obj.tasks.Clone(); }
public InsertTask(ScheduleManager SchedMan, int TaskId) { InitializeComponent(); sm = SchedMan; // копируем задания, чтоб можно было нажать отмена TempTasks = (TaskList)sm.Data.Tasks.Clone(); button4.Text = "Изменить"; numericUpDown1.Value = 1; numericUpDown1.Enabled = false; LoadProduction(); LoadMaterial(); LoadOrders(); int TaskIndex = sm.Data.Tasks.GetIndexById(TaskId); comboBox4.Text = sm.Data.Tasks[TaskIndex].Text; foreach (object item in comboBox1.Items) { if (((ComboBoxItem)item).Id == TempTasks[TaskIndex].ProductionId) { comboBox1.SelectedItem = item; break; } } int ProdIndex = sm.Data.Productions.GetIndexById(TempTasks[TaskIndex].ProductionId); foreach (object item in comboBox3.Items) { if (((ComboBoxItem)item).Id == TempTasks[TaskIndex].SizeIndex) { comboBox3.SelectedItem = item; break; } } foreach (object item in comboBox4.Items) { if (((ComboBoxItem)item).Id == TempTasks[TaskIndex].OrderId) { comboBox4.SelectedItem = item; break; } } foreach (object item in comboBox2.Items) { if (((ComboBoxItem)item).Id == TempTasks[TaskIndex].MaterialId) { comboBox2.SelectedItem = item; break; } } Text = "Изменить задание"; this.taskId = TaskId; }