private void ShowWires(CompositionResult cmp)
        {
            TreeViewItem_Nodes.Items.Clear();

            for (int boardNum = 0; boardNum < cmp.BoardsElements.Count; boardNum++)
            {
                var boardItem = new TreeViewItem();
                boardItem.Header = $"Узел {boardNum + 1}";

                var boardElements = new TreeViewItem();
                boardElements.Header = "Элементы";
                foreach (var element in cmp.BoardsElements[boardNum])
                {
                    var boardElement = new TreeViewItem();
                    if (element != 0)
                    {
                        boardElement.Header = $"D{element}";
                    }
                    else
                    {
                        boardElement.Header = "X";
                    }
                    boardElements.Items.Add(boardElement);
                }

                boardElements.IsExpanded = true;
                boardItem.Items.Add(boardElements);


                var boardWires = new TreeViewItem();
                boardWires.Header = "Провода";
                int wireIterator = 1;
                foreach (var wire in cmp.BoardsWires[boardNum])
                {
                    var itemWire = new TreeViewItem();
                    itemWire.Header = $"Провод {wireIterator}";
                    foreach (var contact in wire)
                    {
                        var itemContact = new TreeViewItem();
                        if (contact.ElementNumber != 0)
                        {
                            itemContact.Header = $"D{contact.ElementNumber}.{contact.ElementContact}";
                        }
                        else
                        {
                            itemContact.Header = "X";
                        }
                        itemWire.Items.Add(itemContact);
                    }
                    boardWires.Items.Add(itemWire);
                    wireIterator++;
                }

                boardWires.IsExpanded = true;
                boardItem.Items.Add(boardWires);


                TreeViewItem_Nodes.Items.Add(boardItem);
            }
        }
Exemple #2
0
        private void OnExportsChanging(object sender, ExportsChangeEventArgs e)
        {
            CompositionResult result = CompositionResult.SucceededResult;

            // Prepare for the recomposition effort by minimizing the amount of work we'll have to do later
            AtomicComposition atomicComposition = e.AtomicComposition;

            IEnumerable <PartManager> affectedParts = this._recompositionManager.GetAffectedParts(e.ChangedContractNames);

            // When in a atomicComposition account for everything that isn't yet reflected in the
            // index
            if (atomicComposition != null)
            {
                EngineContext engineContext;
                if (atomicComposition.TryGetValue(this, out engineContext))
                {
                    // always added the new part managers to see if they will also be
                    // affected by these changes
                    affectedParts = affectedParts.ConcatAllowingNull(engineContext.GetAddedPartManagers())
                                    .Except(engineContext.GetRemovedPartManagers());
                }
            }

            var changedExports = e.AddedExports.ConcatAllowingNull(e.RemovedExports);

            foreach (var partManager in affectedParts)
            {
                result = result.MergeResult(this.TryRecomposeImports(partManager, changedExports, atomicComposition));
            }

            result.ThrowOnErrors(atomicComposition);
        }
Exemple #3
0
        internal static void AreEqual(CompositionResult expected, CompositionResult actual)
        {
            Assert.AreEqual(expected.Succeeded, actual.Succeeded);

            EnumerableAssert.AreSequenceEqual(expected.Errors, actual.Errors, (index, expectedError, actualError) =>
            {
                AreEqual(expectedError, actualError);
            });
        }
 /// <summary>
 ///     Raises the <see cref="ExportsChanging"/> event.
 /// </summary>
 /// <param name="e">
 ///     An <see cref="ExportsChangeEventArgs"/> containing the data for the event.
 /// </param>
 protected virtual void OnExportsChanging(ExportsChangeEventArgs e)
 {
     EventHandler<ExportsChangeEventArgs> changingEvent = this.ExportsChanging;
     if (changingEvent != null)
     {
         CompositionResult result = CompositionServices.TryFire(changingEvent, this, e);
         result.ThrowOnErrors(e.AtomicComposition);
     }
 }
Exemple #5
0
        public static List <StepPlacementLog> Place(CompositionResult cmp, Matrix <int> R, out string errMsg)
        {
            // если в методе произошла какая-то критическая ошибка, записывайте её в эту переменную и делайте return null
            errMsg = "";

            // считываем результат компоновки, в нём хранится список элементов для каждого узла
            var boardsElements = cmp.BoardsElements;

            // создаём класс для логирования (обязательно)
            var log = new List <StepPlacementLog>();

            // создаём список с матрицами для каждого узла
            var boards = new List <Matrix <int> >();

            // тестовый алгоритм просто последовательно размещает все элементы на плату

            // запускаем цикл по платам, в каждой плате резмещаем элементы, а потом переходим к следующей
            foreach (var boardElements in boardsElements)
            {
                // определяем размер платы (3х3, 4х4, 5х5) основываясь на количестве элементов, которые необходимо на ней расположить
                var size = Convert.ToInt32(Math.Ceiling(Math.Sqrt(boardElements.Count)));

                // создаём матрицу просчитанного размера
                var boardMatr = new Matrix <int>(size, size);

                // заполняем "-1" матрицу
                boardMatr.Fill(-1);

                // добавляем в общий список плат новую матрицу платы, в которую будем на этом шаге заносить элементы
                boards.Add(boardMatr);

                // определяет в какую позицию будет поставлен элемент
                int pos = 0;

                // запускаем цикл по элементам, которые должны быть размещены на плате
                foreach (var element in boardElements)
                {
                    // добавляем в последнюю плату элемент на определённую позицию. позиция тут задаётся от 1 до 9. нумерация немного не такая как в идз:
                    // 1 4 7
                    // 2 5 8
                    // 3 6 9 (для платы 3х3)
                    boards.Last().setValueByPlatePos(pos, element);
                    pos++;


                    // записываем результат
                    string msg  = "Поместили элемент D" + element + " на " + boards.Count + " плату"; // пишем сообщение чё произошло на этом шаге
                    var    step = new StepPlacementLog(boards, msg);
                    log.Add(step);
                }
            }

            // возвращаем список шагов
            return(log);
        }
        public void Constructor3_ValuesAsErrorsArgument_ShouldSetErrorsProperty()
        {
            var errors = Expectations.GetCompositionErrors();

            foreach (var e in errors)
            {
                var result = new CompositionResult(e);

                EnumerableAssert.AreEqual(e, result.Errors);
            }
        }
        internal static CompositionResult TryFire <TEventArgs>(EventHandler <TEventArgs> _delegate, object sender, TEventArgs e)
            where TEventArgs : EventArgs
        {
            CompositionResult result = CompositionResult.SucceededResult;

            foreach (EventHandler <TEventArgs> _subscriber in _delegate.GetInvocationList())
            {
                try
                {
                    _subscriber.Invoke(sender, e);
                }
                catch (CompositionException ex)
                {
                    result = result.MergeErrors(ex.Errors);
                }
            }

            return(result);
        }
Exemple #8
0
 /// <summary>
 /// Метод для записи результатов компоновки в файл (сериализация)
 /// </summary>
 public static void WriteComposition(CompositionResult cmp, out string errWrite)
 {
     errWrite = "";
     if (FileName != "")
     {
         try
         {
             using (StreamWriter file = File.CreateText(FileName + ".cmp"))
             {
                 JsonSerializer serializer = new JsonSerializer();
                 serializer.Serialize(file, cmp);
             }
         }
         catch (Exception exc)
         {
             errWrite = $"При записи в файл компоновки произошла ошибка: {exc.Message}";
         }
     }
 }
Exemple #9
0
        /// <summary>
        /// Метод для чтения результатов компоновки в файл (десериализация)
        /// </summary>
        public static CompositionResult ReadComposition(out string msg)
        {
            msg = "";
            CompositionResult cmp = null;

            if (IsFileExists(".cmp", out msg))
            {
                try
                {
                    using (StreamReader file = File.OpenText(FileName + ".cmp"))
                    {
                        JsonSerializer serializer = new JsonSerializer();
                        cmp = (CompositionResult)serializer.Deserialize(file, typeof(CompositionResult));
                    }
                }
                catch (Exception exp)
                {
                    msg = $"Произошла ошибка при попытке чтения файла {FileName}.cmp: {exp.Message}";
                }
            }
            return(cmp);
        }
Exemple #10
0
        private CompositionResult TrySatisfyImportSubset(PartManager partManager,
                                                         IEnumerable <ImportDefinition> imports, AtomicComposition atomicComposition)
        {
            CompositionResult result = CompositionResult.SucceededResult;

            var part = partManager.Part;

            foreach (ImportDefinition import in imports)
            {
                var exports = partManager.GetSavedImport(import);

                if (exports == null)
                {
                    CompositionResult <IEnumerable <Export> > exportsResult = TryGetExports(
                        this._sourceProvider, part, import, atomicComposition);

                    if (!exportsResult.Succeeded)
                    {
                        result = result.MergeResult(exportsResult.ToResult());
                        continue;
                    }
                    exports = exportsResult.Value.AsArray();
                }

                if (atomicComposition == null)
                {
                    result = result.MergeResult(
                        partManager.TrySetImport(import, exports));
                }
                else
                {
                    partManager.SetSavedImport(import, exports, atomicComposition);
                }
            }
            return(result);
        }
        private List <StepCompositionLog> DoComposition()
        {
            var steps = new List <StepCompositionLog>();

            string err_msg = "";

            switch (ComboBox_Method.SelectedIndex)
            {
            case 0:
                steps = PosledGypergraph.Compose(tbCountOfElements.Value ?? 10, tbLimitsOfWires.Value ?? 100, out err_msg);
                break;

            case 1:
                steps = PosledMultigraph.Compose(tbCountOfElements.Value ?? 10, tbLimitsOfWires.Value ?? 100, out err_msg);
                break;

            case 2:
                steps = IterGypergraph.Compose(out err_msg);
                break;

            case 3:
                steps = IterMultigraphNew.Compose(out err_msg);
                break;

            case 4:
                steps = TestComposition.Compose(tbCountOfElements.Value ?? 10, tbLimitsOfWires.Value ?? 100, out err_msg);
                break;
            }

            // если не было ошибки - сериализуем результат
            if (err_msg == "")
            {
                if (steps.Count != 0)
                {
                    var result = new CompositionResult();
                    result.BoardsElements = steps.Last().BoardsList;

                    var sch = ApplicationData.ReadScheme(out err_msg);

                    if (err_msg != "")
                    {
                        MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
                        return(null);
                    }

                    result.CreateBoardsWires(sch, out err_msg);

                    if (err_msg != "")
                    {
                        MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
                        return(null);
                    }

                    // формируем новую матрицу R на основе сформированных проводов, которые были разделены по платам
                    result.MatrixR_AfterComposition = ApplicationData.CreateMatrixR(result.BoardsWires, sch.MatrixR.RowsCount, sch.MatrixR.ColsCount);

                    ApplicationData.WriteComposition(result, out err_msg);

                    if (err_msg != "")
                    {
                        MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
                        return(null);
                    }

                    string msg;
                    if (ApplicationData.IsFileExists(".plc", out msg))
                    {
                        File.Delete($"{ApplicationData.FileName}.plc");
                    }

                    if (ApplicationData.IsFileExists(".trs", out msg))
                    {
                        File.Delete($"{ApplicationData.FileName}.trs");
                    }

                    if (ApplicationData.IsFileExists(".lay", out msg))
                    {
                        File.Delete($"{ApplicationData.FileName}.lay");
                    }

                    mw.MatrControl.UpdateMatrices();
                    mw.PlaceControl.Update();
                    mw.TraceControl.Update();
                    mw.LayerControl.Update();
                }
            }
            if (err_msg != "")
            {
                MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            return(steps);
        }
Exemple #12
0
        public void Compose(CompositionBatch batch)
        {
            ThrowIfDisposed();
            EnsureRunning();

            Requires.NotNull(batch, nameof(batch));

            // Quick exit test can be done prior to cloning since it's just an optimization, not a
            // change in behavior
            if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0))
            {
                return;
            }

            CompositionResult result = CompositionResult.SucceededResult;

            // Get updated parts list and a cloned batch
            var newParts = GetUpdatedPartsList(ref batch);

            // Allow only recursive calls from the import engine to see the changes until
            // they've been verified ...
            using (var atomicComposition = new AtomicComposition())
            {
                // Don't allow reentrant calls to compose during previewing to prevent
                // corrupted state.
                if (_currentlyComposing)
                {
                    throw new InvalidOperationException(SR.ReentrantCompose);
                }

                _currentlyComposing = true;

                try
                {
                    // In the meantime recursive calls need to be able to see the list as well
                    atomicComposition.SetValue(this, newParts);

                    // Recompose any existing imports effected by the these changes first so that
                    // adapters, resurrected parts, etc. can all play their role in satisfying
                    // imports for added parts
                    Recompose(batch, atomicComposition);

                    // Ensure that required imports can be satisfied
                    foreach (ComposablePart part in batch.PartsToAdd)
                    {
                        // collect the result of previewing all the adds in the batch
                        try
                        {
                            ImportEngine.PreviewImports(part, atomicComposition);
                        }
                        catch (ChangeRejectedException ex)
                        {
                            result = result.MergeResult(new CompositionResult(ex.Errors));
                        }
                    }

                    result.ThrowOnErrors(atomicComposition);

                    // Complete the new parts since they passed previewing.`
                    using (_lock.LockStateForWrite())
                    {
                        _parts = newParts;
                    }

                    atomicComposition.Complete();
                }
                finally
                {
                    _currentlyComposing = false;
                }
            }

            // Satisfy Imports
            // - Satisfy imports on all newly added component parts
            foreach (ComposablePart part in batch.PartsToAdd)
            {
                result = result.MergeResult(CompositionServices.TryInvoke(() =>
                                                                          ImportEngine.SatisfyImports(part)));
            }

            // return errors
            result.ThrowOnErrors();
        }
Exemple #13
0
        /// Generates the code that loads the supplied value on the stack
        /// This is not as simple as it seems, as different instructions need to be generated depending
        /// on its type.
        /// We support:
        /// 1. All primitive types
        /// 2. Strings
        /// 3. Enums
        /// 4. typeofs
        /// 5. nulls
        /// 6. Enumerables
        /// 7. Delegates on static functions or any of the above
        /// Everything else cannot be represented as literals
        /// <param name="ilGenerator"></param>
        /// <param name="item"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static void LoadValue(this ILGenerator ilGenerator, object value)
        {
            Assumes.NotNull(ilGenerator);
            CompositionResult result = CompositionResult.SucceededResult;

            //
            // Get nulls out of the way - they are basically typeless, so we just load null
            //
            if (value == null)
            {
                ilGenerator.LoadNull();
                return;
            }

            //
            // Prepare for literal loading - decide whether we should box, and handle enums properly
            //
            Type   valueType = value.GetType();
            object rawValue  = value;

            if (valueType.IsEnum)
            {
                // enums are special - we need to load the underlying constant on the stack
                rawValue  = Convert.ChangeType(value, Enum.GetUnderlyingType(valueType), null);
                valueType = rawValue.GetType();
            }

            //
            // Generate IL depending on the valueType - this is messier than it should ever be, but sadly necessary
            //
            if (valueType == GenerationServices.StringType)
            {
                // we need to check for strings before enumerables, because strings are IEnumerable<char>
                ilGenerator.LoadString((string)rawValue);
            }
            else if (GenerationServices.TypeType.IsAssignableFrom(valueType))
            {
                ilGenerator.LoadTypeOf((Type)rawValue);
            }
            else if (GenerationServices.IEnumerableType.IsAssignableFrom(valueType))
            {
                // NOTE : strings and dictionaries are also enumerables, but we have already handled those
                ilGenerator.LoadEnumerable((IEnumerable)rawValue);
            }
            else if (
                (valueType == GenerationServices.CharType) ||
                (valueType == GenerationServices.BooleanType) ||
                (valueType == GenerationServices.ByteType) ||
                (valueType == GenerationServices.SByteType) ||
                (valueType == GenerationServices.Int16Type) ||
                (valueType == GenerationServices.UInt16Type) ||
                (valueType == GenerationServices.Int32Type)
                )
            {
                // NOTE : Everything that is 32 bit or less uses ldc.i4. We need to pass int32, even if the actual types is shorter - this is IL memory model
                // direct casting to (int) won't work, because the value is boxed, thus we need to use Convert.
                // Sadly, this will not work for all cases - namely large uint32 - because they can't semantically fit into 32 signed bits
                // We have a special case for that next
                ilGenerator.LoadInt((int)Convert.ChangeType(rawValue, typeof(int), CultureInfo.InvariantCulture));
            }
            else if (valueType == GenerationServices.UInt32Type)
            {
                // NOTE : This one is a bit tricky. Ldc.I4 takes an Int32 as an argument, although it really treats it as a 32bit number
                // That said, some UInt32 values are larger that Int32.MaxValue, so the Convert call above will fail, which is why
                // we need to treat this case individually and cast to uint, and then - unchecked - to int.
                ilGenerator.LoadInt(unchecked ((int)((uint)rawValue)));
            }
            else if (valueType == GenerationServices.Int64Type)
            {
                ilGenerator.LoadLong((long)rawValue);
            }
            else if (valueType == GenerationServices.UInt64Type)
            {
                // NOTE : This one is a bit tricky. Ldc.I8 takes an Int64 as an argument, although it really treats it as a 64bit number
                // That said, some UInt64 values are larger that Int64.MaxValue, so the direct case we use above (or Convert, for that matter)will fail, which is why
                // we need to treat this case individually and cast to ulong, and then - unchecked - to long.
                ilGenerator.LoadLong(unchecked ((long)((ulong)rawValue)));
            }
            else if (valueType == GenerationServices.SingleType)
            {
                ilGenerator.LoadFloat((float)rawValue);
            }
            else if (valueType == GenerationServices.DoubleType)
            {
                ilGenerator.LoadDouble((double)rawValue);
            }
            else
            {
                throw new InvalidOperationException(
                          string.Format(CultureInfo.CurrentCulture, Strings.InvalidMetadataValue, value.GetType().FullName));
            }
        }
Exemple #14
0
        public static List <StepPlacementLog> Place(CompositionResult cmp, Matrix <int> R, out string errMsg)
        {
            matrR = R;
            // если в методе произошла какая-то критическая ошибка, записывайте её в эту переменную и делайте return null
            errMsg = "";

            // считываем результат компоновки, в нём хранится список элементов для каждого узла
            var boardsElements = cmp.BoardsElements;

            // создаём класс для логирования (обязательно)
            var log = new List <StepPlacementLog>();

            // создаём список с матрицами для каждого узла
            var boards = new List <Matrix <int> >();

            // запускаем цикл по платам, в каждой плате резмещаем элементы, а потом переходим к следующей
            foreach (var boardElements in boardsElements)
            {
                // определяем размер платы (3х3, 4х4, 5х5) основываясь на количестве элементов, которые необходимо на ней расположить
                var size = Convert.ToInt32(Math.Ceiling(Math.Sqrt(boardElements.Count)));

                // создаём матрицу просчитанного размера
                var boardMatr = new Matrix <int>(size, size);

                // заполняем "-1" матрицу
                boardMatr.Fill(-1);

                // добавляем в общий список плат новую матрицу платы, в которую будем на этом шаге заносить элементы
                boards.Add(boardMatr);

                // начальная позиция - условные координаты разъема
                var pos = new Position(-1, -1);

                // таким способом копируем список всех элементов в список неразмещённых
                List <int> unplacedElements = boardElements.Select(x => x).ToList();

                // в списке размещённых по умолчанию только разъём
                List <int> placedElements = new List <int>();
                placedElements.Add(0);

                // запускаем цикл, пока не разместим все элементы
                while (unplacedElements.Count > 0)
                {
                    // список с количеством связей с ранее размещёнными элементами ещё неразмещённых
                    // позиция в списке совпадает с позицией в списке неразмещённых номеров элементов
                    var countRelationWithPlaced = new List <int>();

                    // с помощью метода получаем список количества связей для каждого неразмещённого элемента
                    countRelationWithPlaced = countRelations(unplacedElements, placedElements);

                    // определяем максимальное число связей
                    var maxRelations = countRelationWithPlaced.Max();

                    // определяем позицию, в которой находится элемент с максимальным количеством связей
                    var elementPosMaxRelations = countRelationWithPlaced.IndexOf(maxRelations);

                    // получаем номер элемента по позиции в списке
                    var elementNumberMaxRelations = unplacedElements[elementPosMaxRelations];

                    string msg = "Количество связей с размещёнными элементами неразмещённых: ";
                    for (int i = 0; i < unplacedElements.Count; i++)
                    {
                        msg += $"D{unplacedElements[i]}={countRelationWithPlaced[i]}; ";
                    }
                    msg += "\n";
                    msg += $"Максимальное количество c размещёнными элементами у элемента D{elementNumberMaxRelations}\n";
                    msg += $"Найдём оптимальную позицию:\n";

                    // получаем список незанятых соседних ячеек на основе позиции элемента размещённого на предыдущем шаге
                    var neighbors = getNeigbors(boardMatr, pos);

                    // начинаем определение оптимальной позиции для размещения элемента
                    Position minLpos = null;
                    int      minL    = int.MaxValue;
                    // запускаем цикл по всем соседям
                    foreach (var neighbor in neighbors)
                    {
                        msg += $"D{elementNumberMaxRelations} -> {boardMatr.getRelativePosByAbsolute(neighbor)}; L=";
                        List <string> operations = new List <string>();
                        int           L          = 0;
                        // запускаем цикл по всем элементам
                        for (int j = 0; j < matrR.ColsCount; j++)
                        {
                            // если этот элемент был размещён
                            if (placedElements.Contains(j))
                            {
                                // если у размещаемого элемента есть связи с текущим рассматриваемым
                                if (matrR[elementNumberMaxRelations, j] != 0)
                                {
                                    // количество связей определяем по матрице R
                                    int countRelationsWithElement = matrR[elementNumberMaxRelations, j];
                                    // получаем расстояние между элементами
                                    int length = getLength(neighbor, getPosByElementNumber(boardMatr, j));
                                    operations.Add($"{countRelationsWithElement}*{length}");
                                    // суммируем длину умноженную на количество связей в L
                                    L += countRelationsWithElement * length;
                                }
                            }
                        }
                        msg += String.Join("+", operations);
                        msg += $"={L}\n";
                        // если подсчитанное L меньше просчитанного на предыдущих шагах
                        if (L < minL)
                        {
                            minL = L;
                            // принимаем эту позицию как оптимальную
                            minLpos = neighbor.Clone();
                        }
                    }
                    int minLposRelative = boardMatr.getRelativePosByAbsolute(minLpos);
                    msg += $"Минимальное значение L в {minLposRelative} позиции\n";
                    pos  = minLpos.Clone();

                    // устанавливаем элемент в оптимальную позицию
                    boards.Last().setValueByPlatePos(minLposRelative, elementNumberMaxRelations);

                    // начинаем логирование действия

                    msg += $"Помещаем его в {minLposRelative} позицию на {boards.Count} плату";
                    var step = new StepPlacementLog(boards, msg);
                    log.Add(step);
                    // закончили логирование

                    // убираем из списка неразмещённых элемент, который только что разместили
                    unplacedElements.Remove(elementNumberMaxRelations);
                    // и добавляем в список размещённых
                    placedElements.Add(elementNumberMaxRelations);
                }
            }
            return(log);
        }
        public void Constructor3_EmptyAsErrorsArgument_ShouldSetSucceededPropertyToTrue()
        {
            var result = new CompositionResult(Enumerable.Empty<CompositionError>());

            Assert.IsTrue(result.Succeeded);
        }
        public void Constructor3_ValuesAsErrorsArgument_ShouldSetSucceededPropertyToTrueIfThereAreErrors()
        {
            var errors = Expectations.GetCompositionErrors();

            foreach (var e in errors)
            {
                var result = new CompositionResult(e);

                if (e.Count() > 0)
                {
                    Assert.IsFalse(result.Succeeded);
                }
                else
                {
                    Assert.IsTrue(result.Succeeded);
                }
            }
        }
Exemple #17
0
        }                                                          // список плат, в котором хранится список проводов по 2 контакта для каждой платы

        public void CreateBoardsDRPs(CompositionResult cmp, List <int> dips, out string err)
        {
            err = "";
            var elInBoards  = cmp.BoardsElements;
            var boardsWires = cmp.BoardsWires;

            if (BoardsMatrices == null)
            {
                err = "Список плат пустой";
                return;
            }
            if (BoardsMatrices.Count == 0)
            {
                err = "Список плат пустой";
                return;
            }


            // список в котором будет хранится размер разъёма для каждой платы
            var BoardsCountContactsConnector = new List <int>();

            BoardsElementsContactsPos = new List <Dictionary <int, List <Position> > >();
            BoardsDRPs = new List <Matrix <Cell> >();

            // запускаем цикл для формирования своего дрп для каждого узла
            for (int numBoard = 0; numBoard < BoardsMatrices.Count; numBoard++)
            {
                int countContactsConnector = 0;

                countContactsConnector = boardsWires[numBoard].Count(x => x.Any(y => y.ElementNumber == 0));

                BoardsCountContactsConnector.Add(countContactsConnector);


                // расчёт размера ДРП платы
                int drpHeight = 0;
                int drpWidth  = 0;
                var brdMatr   = BoardsMatrices[numBoard];

                // подсчитываем необходимую высоту платы
                // запускаем цикл по столбцам, и определяем его высоту суммируя размер для каждого элемента
                for (int j = 0; j < brdMatr.ColsCount; j++)
                {
                    int currentColHeight = 0;
                    for (int i = 0; i < brdMatr.RowsCount; i++)
                    {
                        int elementNumber = brdMatr[i, j];
                        if (elementNumber != -1) // пропускаем пустые места
                        {
                            int elementDip   = dips[elementNumber];
                            int pinsInColumn = elementDip / 2;
                            currentColHeight += ApplicationData.ElementsDistance + pinsInColumn + (ApplicationData.PinDistance * pinsInColumn) - ApplicationData.PinDistance;
                        }
                    }
                    if (currentColHeight > drpHeight)
                    {
                        drpHeight = currentColHeight;
                    }
                }

                // подсчитываем необходимую ширину платы
                for (int i = 0; i < brdMatr.RowsCount; i++)
                {
                    int currentRowWidth = 0;
                    for (int j = 0; j < brdMatr.ColsCount; j++)
                    {
                        int elementNumber = brdMatr[i, j];
                        if (elementNumber != -1) // пропускаем пустые места
                        {
                            int elementDip = dips[elementNumber];
                            currentRowWidth += ApplicationData.ElementsDistance + 2 + ApplicationData.RowDistance;
                        }
                    }
                    if (currentRowWidth > drpWidth)
                    {
                        drpWidth = currentRowWidth;
                    }
                }

                drpHeight += ApplicationData.ElementsDistance;
                drpWidth  += ApplicationData.ElementsDistance + 2; // ширина + 2, чтобы учесть разъём

                // создаём итоговое дрп на базе расчётов
                var boardDRP = new Matrix <Cell>(drpHeight, drpWidth);

                // заполняем его пустыми ячейками
                for (int drpRow = 0; drpRow < boardDRP.RowsCount; drpRow++)
                {
                    for (int drpCol = 0; drpCol < boardDRP.ColsCount; drpCol++)
                    {
                        boardDRP[drpRow, drpCol] = new Cell();
                    }
                }

                // создаём словарь координат контактов разъёма и элементов
                var ElementsContactsPos = new Dictionary <int, List <Position> >();

                // переходим к размещению разъёма
                var heightConnector = BoardsCountContactsConnector.Last();

                int startRowConnector = drpHeight / 2 - heightConnector / 2;

                var ConnectorContactsPos = new List <Position>();
                for (int r = 0; r < heightConnector; r++)
                {
                    boardDRP[startRowConnector + r, r % 2].State = CellState.Contact;
                    ConnectorContactsPos.Add(new Position(startRowConnector + r, r % 2));
                }

                ElementsContactsPos.Add(0, ConnectorContactsPos);


                Position startPos   = new Position(ApplicationData.ElementsDistance, ApplicationData.ElementsDistance + 2);
                Position currentPos = new Position(ApplicationData.ElementsDistance, ApplicationData.ElementsDistance + 2);


                // запускаем цикл по столбцам матрицы, в которой хранятся номера элементов
                for (int j = 0; j < brdMatr.ColsCount; j++)
                {
                    // запускаем цикл по строкам матрицы, в которой хранятся номера элементов
                    for (int i = 0; i < brdMatr.RowsCount; i++)
                    {
                        // узнаём номер элемента в позиции
                        int elementNumber = brdMatr[i, j];

                        // если -1 - значит место не занято
                        if (elementNumber != -1) // пропускаем пустые места
                        {
                            // список координат каждого контакта
                            var ElementContactsPos = new List <Position>();

                            // добавляем заглушку, т.к. нумерация ножек начинается с 1, а у нас список и 0 элемент должен существовать
                            ElementContactsPos.Add(new Position(-1, -1));

                            int elementNumberLabelRow    = currentPos.Row;
                            int elementNumberLabelColumn = currentPos.Column + (int)Math.Ceiling((double)ApplicationData.RowDistance / 2);

                            boardDRP[elementNumberLabelRow, elementNumberLabelColumn].Description = $"D{elementNumber}";

                            // узнаём номер дипа
                            int elementDip = dips[elementNumber];
                            // количество контактов в столбце = номер дипа / 2
                            int pinsInColumn = elementDip / 2;
                            int offsetRow    = 0;
                            // сначала формируем первый ряд контактов элемента сверху вниз
                            boardDRP[currentPos.Row + offsetRow, currentPos.Column].Description = "(X)";
                            while (offsetRow < (pinsInColumn * (ApplicationData.PinDistance + 1)) - ApplicationData.PinDistance)
                            {
                                boardDRP[currentPos.Row + offsetRow, currentPos.Column].State = CellState.Contact;
                                // записываем текущую координату в список координат контактов
                                ElementContactsPos.Add(new Position(currentPos.Row + offsetRow, currentPos.Column));
                                offsetRow += 1 + ApplicationData.PinDistance;
                            }
                            offsetRow -= 1 + ApplicationData.PinDistance;
                            // сдвигаемся вправо на расстояние в клетках от первого ряда контактов
                            currentPos.Column += ApplicationData.RowDistance + 1;
                            // теперь идём обратно вверх
                            while (offsetRow >= 0)
                            {
                                boardDRP[currentPos.Row + offsetRow, currentPos.Column].State = CellState.Contact;
                                // записываем текущую координату в список координат контактов
                                ElementContactsPos.Add(new Position(currentPos.Row + offsetRow, currentPos.Column));
                                offsetRow -= 1 + ApplicationData.PinDistance;
                            }
                            // добавляем сформированный список координат каждого контакта
                            ElementsContactsPos.Add(elementNumber, ElementContactsPos);

                            // возвращаемся опять в позицию для печати первого ряда контактов, но уже следующего элемента
                            currentPos.Column -= ApplicationData.RowDistance + 1;
                            // пропускаем ячейки с уже размещённым элементом
                            currentPos.Row += (pinsInColumn * (ApplicationData.PinDistance + 1)) - ApplicationData.PinDistance;

                            currentPos.Row += ApplicationData.ElementsDistance;
                        }
                        else
                        {
                            // если позиция пустая, то нужно пропустить определённое количество клеточек
                            // формула приблизительная
                            currentPos.Row += drpHeight / (brdMatr.RowsCount + 1);
                        }
                    }
                    // возвращаемся к начальной точке размещения элементов
                    currentPos.Row    = startPos.Row;
                    currentPos.Column = startPos.Column;
                    // пропускаем определённое количество столбцов, которое определяется по количеству уже размещённых умноженное на отступы
                    currentPos.Column += ((j + 1) * (ApplicationData.RowDistance + 2)) + ((j + 1) * ApplicationData.ElementsDistance);
                }

                BoardsDRPs.Add(boardDRP);
                BoardsElementsContactsPos.Add(ElementsContactsPos);
            }

            return;
        }
        public void Compose(CompositionBatch batch)
        {
            this.ThrowIfDisposed();
            this.EnsureRunning();

            Requires.NotNull(batch, "batch");

            // Quick exit test can be done prior to cloning since it's just an optimization, not a
            // change in behavior
            if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0))
            {
                return;
            }

            CompositionResult result = CompositionResult.SucceededResult;

            // Clone the batch, so that the external changes wouldn't happen half-way thorugh compose
            // NOTE : this does not guarantee the atomicity of cloning, which is not the goal anyway,
            // rather the fact that all subsequent calls will deal with an unchanging batch
            batch = new CompositionBatch(batch.PartsToAdd, batch.PartsToRemove);

            var newParts = GetUpdatedPartsList(batch);

            // Allow only recursive calls from the import engine to see the changes until
            // they've been verified ...
            using (var atomicComposition = new AtomicComposition())
            {
                // Don't allow reentrant calls to compose during previewing to prevent
                // corrupted state.
                if (this._currentlyComposing)
                {
                    throw new InvalidOperationException(Strings.ReentrantCompose);
                }

                this._currentlyComposing = true;

                try
                {
                    // In the meantime recursive calls need to be able to see the list as well
                    atomicComposition.SetValue(this, newParts);

                    // Recompose any existing imports effected by the these changes first so that
                    // adapters, resurrected parts, etc. can all play their role in satisfying
                    // imports for added parts
                    this.Recompose(batch, atomicComposition);

                    // Ensure that required imports can be satisfied
                    foreach (ComposablePart part in batch.PartsToAdd)
                    {
                        // collect the result of previewing all the adds in the batch
                        try
                        {
                            this._importEngine.PreviewImports(part, atomicComposition);
                        }
                        catch (ChangeRejectedException ex)
                        {
                            result = result.MergeResult(new CompositionResult(ex.Errors));
                        }
                    }

                    result.ThrowOnErrors(atomicComposition);

                    // Complete the new parts since they passed previewing.`
                    using (this._lock.LockStateForWrite())
                    {
                        this._parts = newParts;
                    }

                    atomicComposition.Complete();
                }
                finally
                {
                    this._currentlyComposing = false;
                }
            }

            // Satisfy Imports
            // - Satisfy imports on all newly added component parts
            foreach (ComposablePart part in batch.PartsToAdd)
            {
                result = result.MergeResult(CompositionServices.TryInvoke(() =>
                                                                          this._importEngine.SatisfyImports(part)));
            }

            // return errors
            result.ThrowOnErrors();
        }
        public void Constructor1_ShouldSetErrorsPropertyToEmptyEnumerable()
        {
            var result = new CompositionResult();

            EnumerableAssert.IsEmpty(result.Errors);
        }
        public void Constructor3_NullAsErrorsArgument_ShouldSetErrorsPropertyToEmptyEnumerable()
        {
            var result = new CompositionResult((IEnumerable<CompositionError>)null);

            EnumerableAssert.IsEmpty(result.Errors);
        }
        public void Constructor2_NullAsErrorsArgument_ShouldSetSucceededPropertyToTrue()
        {
            var result = new CompositionResult((CompositionError[])null);

            Assert.IsTrue(result.Succeeded);
        }
        public void Constructor1_ShouldSetSucceededPropertyToTrue()
        {
            var result = new CompositionResult();

            Assert.IsTrue(result.Succeeded);
        }
        public void Constructor3_EmptyAsErrorsArgument_ShouldSetErrorsPropertyToEmptyEnumerable()
        {
            var result = new CompositionResult(Enumerable.Empty<CompositionError>());

            EnumerableAssert.IsEmpty(result.Errors);
        }