Дипломная (вкр): Программный комплекс моделирования релейно-контактных схем

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

При выборе инструмента в окне программы высвечивается название выбранного инструмента и по нажатию левой кнопки мыши из функции onLeft(event) вызывается функция данного инструмента, как показано на рисунке 5.15. Инструмент должен работать тогда, когда он выбран на панели инструментов, для того и делаются все проверки.

Рисунок 5.13 - Код функции NewID()

Рисунок 5.14 - Интерфейс с новыми инструментами

Рисунок 5.15 - Выбор необходимого инструмента

Так как инструментов предполагается большое количество и интерфейс будет перерабатываться, то сейчас в один блок сгруппированы только пять инструментов в коде. В интерфейсе сгруппированы в один блок инструменты выбора элемента. Для редактирования отдельного элемента сгруппированы еще два инструмента, а инструмент стирания схемы выделен отдельно, чтобы случайно его не нажать. Отображается это так, как на рисунке 5.16

Рисунок 5.16 - Демонстрация выбора инструмента

При выбранном инструменте «Провод» можно рисовать провода между шинами и контактами и реле, между контактами и между контактами и реле. Показано на рисунке 5.17. Необходимо, чтобы на схеме был хотя бы один контакт и одно реле. Чтобы избежать лишних ошибок при построении схемы сделана эта проверка.

Провода рисуются функциями rightDown(event) и rightUp(event), то есть происходит обработка события нажатия правой кнопки мыши, как показано на рисунке 5.18.

Рисунок 5.18 - Функции rightDown(event) и rightUp(event)

В программе отображение проводов при размещенных на схеме контакте и реле выглядит, как на рисунке 5.19. Геометрия провода просчитывается автоматически.

Рисунок 5.19 - Отображение проводов на схеме

Чтобы редактировать названия элементов используется инструмент «Редактировать». Он работает по двойному клику левой кнопки мыши на элементе. В программе открывается диалоговое окно, в котором вносятся значения этих элементов. Код показан на рисунке 5.20.

Рисунок 5.20 - Код инструмента редактирования элементов

В программе это отображается так, как показано на рисунке 5.21.

Рисунок 5.21 - Диалоговое окно инструмента редактирования элементов

При нажатии на кнопку «Подтвердить» происходит действие, как на рисунке 5.22. То есть изменяется название элемента, контакта, как в данном случае. Также в таблицу элементу вносится изменение переменной line, то есть теперь этот элемент находится в определенной цепи схемы.

Рисунок 5.22 - Результат редактирования элемента

Функция setValues(nameVal, lineVal) необходима для установления значения элемента. Вызывается из функции diaologOfSettings(count, name, line). Код ее показан на рисунке 5.23.

Рисунок 5.23 - Функция установки значений элементов

6. РЕАЛИЗАЦИЯ ПРОГРАММНЫХ МОДУЛЕЙ

Преимущество языка Lua является возможность использования пользовательских функций. То есть выделения части кода конструкцией function name() … end и вызовом этой функций из любой другой. Такой способ позволяет быстро и удобно редактировать код, находить ошибки и исправлять их, изменять программные процессы и так далее. Переменные в этом языке можно объявлять где угодно, то есть либо заранее, до начала основного кода, либо в теле функций. Правда нужно учитывать, что, если переменная объявлена в теле функции и она является локальной (перед ней написано слово local), то она будет доступна только в этой функции. Глобальные же переменные (без слова local) доступны из любой части кода.

Моя разработка состоит из двух программ: имитатора работы схемы и редактора схем. Общее у этих двух программ - таблицы с одинаковыми полями. Такие, как contacts (хранит данные о контактах), relays (содержит данные о катушках реле), wires (хранит данные о координатах проводов), lines (эта таблица содержит данные о «линиях» для нахождения цепи срабатывания контактов и реле).

6.1 Алгоритмы программы-имитатора

Функция painter(event). Работает следующим образом. В первую очередь происходит объявление переменной dc - теперь она будет давать доступ к отрисовке линий, фигур, текста и тому подобного из этой функции. Осуществляется с помощью библиотеки wxWidgets. Далее, если переменная textdef не является пустой (nil), а изначально она именно такой и является, так как нигде не объявлена, то программа выводит на экран по необходимым координатам сообщение «Сработала защита: Название защиты». Если же никакая защита не сработала, то есть переменная до сих пор пустая, то выводится лишь сообщение «Сработала защита:». Эта переменная переназначается в одной из последующих функций. Далее идут конструкторы линий dc:DrawLine(x, y, x1, y1) - рисуются две главные питающие шины схемы. Так как они необходимы всегда и находятся на одном и том же месте, то им можно задать точные координаты, как в моем примере.

Следующий блок кода отвечает за проверку катушек реле, то есть активированы они или нет. Сначала проверяется, не пуста ли таблица relays. Делается это для того, чтобы избежать ошибок в последующих вычислениях. Если таблица не пуста, то сравниваются id контактов и реле в своих таблицах. Если реле не активны, то и контакты находятся в нормальном состоянии. После этого отображаются сами реле на схеме с помощью нескольких конструкторов dc:DrawLine(x, y, x1, y1). Изначальные координаты берутся из таблицы relays, остальные отсчитываются от них. Название реле также берется из таблицы и положение его отсчитывается от первоначальных координат. Для отображения названий контактов и реле используется конструктор dc:DrawText(“string”, x, y).

Подобные действия проделываются и для контактов. Сначала проверяется таблица contacts на то, что она не пустая. Затем в самой таблице проверяется каким является контакт: нормально открытым или закрытым (значение берется из таблицы). Так же из таблицы берется значение проводит ли контакт ток в данный момент или не проводит и, в зависимости от этих состояний рисуется контакт тем же способом, что и реле, включая название контакта. Все координаты отсчитываются от изначальных, указанных в таблице. Такие же действия проводятся с таблицей wires. То есть, данная функция отвечает только за отрисовку элементов. При этом, она будет вызываться из других функций командой panel:Refresh() и перерисовывать схему в соответсвии с новыми данными в таблицах contacts и relays.

Следующая функция onDown(event) производит обработку события нажатия правой кнопки мыши. Сначала происходит проверка контакта на нормальное состояние, а затем сравниваются координаты указателя мыши и контакта. Если найденный контакт является нормально открытым, то теперь он может проводить ток (active=true в таблице этого контакта изменяется состояние active с false на true), для нормально закрытого контакта наоборот - active становится false, то есть он не проводит теперь ток. Назначается переменная line, значение которой берется из таблицы contacts для данного контакта. И переназначается переменная textdef, которая описывалась в предыдущей функции. После этого вызывается repaint() - функция, необходимая для переназначения данных в таблицах contacts и relays и вызова перерисовки самой схемы.

Функция repaint() работает следующим образом. Сначала объявляются таблицы lines и linescon, при этом в первую записываются значения из файла-сохранения, а во вторую - при дальнейших вычислениях.

Сравниваются значения состояний контактов (active), находящихся в одной «линии» и, если они все активны, то выполняется оставшийся код функции. При совпадении id контакта с id реле в своих таблица, состояние этого контакта инвертируется, так как на реле подано напряжение и сердечник притягивает движущуюся часть реле, которая перемещает группы контактов. Контакты, находящиеся на этом реле находятся в своих «линиях», поэтому в таблицу linescon записываются уже значения line этих инвертированных контактов. Необходимо это для того, чтобы активировать реле, находящиеся в «линиях» с этими контактами. За что и отвечает оставшийся код, в котором происходит все то же самое, что и для первых контактов-реле. Затем происходит перерисовка схемы командой panel:Refresh().

Функция onUp(event). Как можно догадаться, эта функция обрабатывает событие «отпускания» правой кнопки мыши. Работает аналогично функциям onDown(event) и repaint() одновременно, только все значения инвертируются к исходному состоянию.

Функция table.load(filename) необходима для десериализации таблицы, находящейся в файле-сохранении. Необходимо уточнить, что в Lua невозможно выводить таблицы в файл напрямую, поэтому их нужно переводить в строки, то есть сериализовать. Соответственно обратное действие - десериализация, необходима для того, чтобы из строки получить таблицу в изначальном ее состоянии, которая назначается переменной tables[1]. Далее происходит вызов функции setValues(newTable) с передаваемым параметром tables[1]. Происходит это так: setValues(tables[1]).

Функция setValues(newTable) необходима для того, передать данные из таблицы tables[1] из файла-сохранения в рабочие таблицы contacts, relays, wires и lines. Не совсем правильно сохранять в файл каждую таблицу отдельно, так как это вызовет путаницу в сохранении и при загрузке может получиться не тот результат, который ожидался. Плюс, таким образом от сложного приходим к простому и порядок таблиц в файле-сохранении не меняется. Поэтому в редакторе эти четыре таблицы помещаются в одну общую. В имитаторе же эта таблица при загрузке схемы «распаковывается» и позволяет отрисовывать схему. Также строковые данные состояния active контактов переводятся в значения true или false. Сохраняется в стороковом формате из-за того, что переменные типа Boolean нельзя перевести в строку функцией сериализации. В итоге это поле просто пропадает и схема работает не правильно. Именно для этого и сделаны дополнительные переводы. Реле всегда находятся изначально в неактивированном состоянии, поэтому их значения active становятся false. Это назначение происходит только в программе-имитаторе, так как нет смысла производить дополнительные переводы в редакторе схем, потому что все реле всегда, до включения схемы находятся в нормально отключенном состоянии. Далее вызывается команда panel:Refresh() и схема обновляется, то есть перерисовывается. Работу этой программы можно изобразить блок-схемой, как на рисунке 6.1.

6.2 Алгоритмы редактора схем

Переменные таблиц имеют те же имена, что и в имитаторе. Также с ним совпадает функция painter(event), с единственным отличием - чтобы программа не выдавала ошибку, дополнительно проверяется, что переменная с именем контакта или реле не пустая в своей таблице.

На панели инструментов имеются кнопки, которые отвечают за свой элемент схемы: контакт, катушка, провод и так далее.

Рисунок 6.1 - Блок-схема работы программы-имитатора

Эта функция обрабатывает событие нажатия левой кнопки мыши. В зависимости от значения переменной tool вызывается одна из следующих функций: drawOpenCont() - рисуется нормально открытый контакт и в таблицу contacts заносятся его значения (координаты, состояние, «проводимость», название, линия); drawCloseCont() - то же самое для закрытого контакта; drawRelay() - то же самое для катушки реле; clearSingle() вместо того, чтобы очистить всю область схемы, благодаря этой функции можно стирать по одному элементу. Когда находится совпадение в таблицах contacts или relays, тогда по индексу этого элемента из нужной таблицы удаляется значение командой table.remove(name, pos) (name - имя таблицы, pos - позиция в таблице). После выполнения действия функции происходит обновление схемы командой panel:Refresh().

Функции rightDown(event) и rightUp(event) работают совместно и необходимы для прокладки проводов на схеме, обрабатывают они события нажатия и отпускания правой кнопки мыши. Есть четыре шага: нажатие и отпускание правой кнопки мыши на первом из соединяемых элементов и нажатие и отпускание ее на втором из соединяемых элементов. Сначала переменная step = 1, когда происходит четвертое действие или шаг, то есть step = 4, то эта переменная вновь становится равна единице. Провод может быть нарисован от питающей шины до контакта, от одного контакта до другого, от контакта до реле, от реле или контакта до второй питающей шины. Если есть совпадение координат мыши с одним из элементов из таблиц contacts или relays, либо с координатами питающих шин, то провод отрисовывается. В ином случае - нет. Также, для того, чтобы проложить провод, необходимо, чтобы на схеме был хотя бы один контакт и одна катушка реле. В функции rightUp(event) при срабатывании события отпускания правой кнопки мыши, в зависимости от состояния переменной step, происходит следующее: переменная step изменяет свое значение на заданное и при значении ее, равном четырем, в таблицу wires заносятся координаты провода. После этого схема обновляется командой panel:Refresh(). Необходимо, также, добавить, что функции эти работают только тогда, когда на панели инструментов выбран инструмент «Провод», а значит установлено необходимое значение переменной tool.

Функция onDoubleClick(event) обрабатывает двойной клик левой кнопки мыши. Работает тогда, когда на панели инструментов выбран инструмент «Редактировать», а значит установлено необходимое значение переменной tool. При совпадении координат мыши с координатами контакта или реле в своих таблицах, вызывается функция dialogOfSettings(name, line), в которую передаются данные о названии элемента и его линии. Эти параметры берутся из таблицы элемента.

Функция dialogOfSettings(name, line) создает диалоговое окно с двумя полями для ввода текста «Название» и «Линия» и с кнопкой «Подтвердить». Изначально в этих полях указаны название редактируемого элемента и его линия. При изменении значений данных полей и нажатии кнопки «Подтвердить» происходит переназначение переменных name и line в таблице контакта или реле. Происходит это в функции setValues(nameVal, lineVal) (nameVal и lineVal - передаваемые значения).

Функция setValues(nameVal, lineVal) работает следующим образом. Из диалога в нее передаются значения названия и линии контакта или реле. Также в функции onDoubleClick(event) назначались переменные с координатами контакта или реле (для того и другого свои), а так как эти переменные являются глобальными, то они доступны из любой функции. В setValues(nameVal, lineVal) ищется совпадение координат, полученных в функции onDoubleClick(event) и координат в таблицах contacts и relays и если оно находится, то данному элементу устанавливаются значения переменных name и line, полученные из диалога редактирования, в своих таблицах. Необходимо, также, учитывать, что id контакта и id реле должны быть одинаковыми, когда контакт расположен на этом реле, при этом, если контакт находится на реле, то он всегда имеет в своем названии часть названия реле. Поэтому для контакта ищется совпадение названия с названием реле и уже из этого совпадения контакту назначается id его реле. После всех этих операций происходит обновление схемы командой panel:Refresh().

Функция saveSchema() необходима для сохранения схемы в файл. Чтобы сохранить схему в файл необходимо таблицу сериализовать, то есть перевести в строку. Данная функция для этого и используется. Она вызывается из меню сохранения. В нее вносится общая таблица с таблицами contacts, relays, wires, lines и путь к файлу-сохранению.

Функция кнопки «Очистить» на панели инструментов работает следующим образом: при нажатии на эту кнопку таблицы contacts, relays и wires обнуляются, то есть становятся пустыми и схема обновляется командой panel:Refresh().

Необходимо также сказать, что в библиотеке wxWidgets есть зарезервированные id для некоторых функций. Например, для кнопок меню, таких как «Сохранить», «Новый», «Открыть» и так далее. Но может возникнуть ситуация, когда этих id может быть недостаточно или для них нужны иные функции. В моем случае - это, например, выбор инструментов на панели инструментов. Для них нет зарезервированных значений этого парметра, поэтому их id назначается с помощью функции newID(). В этом случае каждому названию этого параметра инструмента устанавливается свое значение, отсчитываемое от максимального зарезервированного id, увеличиваемого с каждым новым на единицу. Это позволяет сделать каждый инструмент индивидуальным и не вносить путаницу в пункты меню и кнопки панели инструментов. Изобразить работу этой программы можно следующей блок-схемой, как на рисунке 6.2.

Источник: https://www.bibliofond.ru/detail.aspx?id=896854