close

Вход

Забыли?

вход по аккаунту

?

Отчет КТО(1)

код для вставкиСкачать
Министерство образования
Российской Федерации
Управление учебных заведений высшего профессионального
образования Тверской государственный технический университет
Кафедра ЭВМ
СОГЛАСОВАНО УТВЕРЖДАЮ
Гл. специалист предприятия Зав.кафедрой ЭВМ
(для которого выполнена
реальная работа) ______________ В.А.Григорьев
_____________________________ подпись, инициалы, фамилия "___"____________2003 г. "___"__________2003 г.
ПОЯСНИТЕЛЬНАЯ ЗАПИСКА
к курсовой работе по конструкторско-технологическому обеспечению
на тему "Разработка алгоритмического и программного обеспечения модуля волновой трассировки при печатном монтаже".
Автор проекта :____________ Булычев Д. Н.
подпись, инициалы, фамилия
Специальность 2201, ВМКСС
номер, наименование Обозначение курсового проекта (работы) _________Группа ЭВМ-43
Руководитель проекта____________________Лебедев В.В.
подпись, дата Проект защищен ___________ Оценка_________
Члены комиссии:
_______________________ ______________________
подпись, дата инициалы, фамилия
_______________________ ______________________
подпись, дата инициалы, фамилия
_______________________ ______________________
подпись, дата инициалы, фамилия
Тверь 2003 г.
город, год защиты
Министерство образования
Российской Федерации
Управление учебных заведений высшего профессионального
образования Тверской государственный технический университет
Кафедра ЭВМ
ЗАДАНИЕ НА КУРСОВОЙ ПРОЕКТ (РАБОТУ)
Студент: Булычев Д. Н., код_980101__ группа ЭВМ-43
фамилия, инициалы
1. Тема: Разработка программного средства 2. Срок представления проекта к защите "____"__________2003г.
3. Исходные данные для проектирования (научного исследования)
________________________________________________________________________________________________________________________________
4. Содержание пояснительной записки курсового проекта (работы)
ВВЕДЕНИЕ. ТЕОРЕТИЧЕСКАЯ ЧАСТЬ
СПЕЦИАЛЬНАЯ ЧАСТЬ. ОПИСАНИЕ РАЗРАБОТАННОГО ПРОГРАММНОГО СРЕДСТВА
ЗАКЛЮЧЕНИЕ
СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ
ПРИЛОЖЕНИЕ 1. ЛИСТИНГ ПРОГРАММЫ
5. Перечень графического материала:_______________________________
_______________________________________________________________
Руководитель проекта (работы) ________________ _________________
подпись, дата инициалы, фамилия Задание принял к исполнению ____________ "___"___________2003г.
подпись
СОДЕРЖАНИЕ
ВВЕДЕНИЕ4
ТЕОРЕТИЧЕСКАЯ ЧАСТЬ5
1. Общая постановка задачи трассировки задачи трассировки5
2. Трассировка проводного монтажа.5
3. Волновой алгоритм решения задачи трассировки и трассировка в каналах11
ПРОГРАММНОГО СРЕДСТВА17
1. Назначение и особенности программы17
2. Руководство пользователя18
2.1 Главное меню18
2.2 Панель инструментов.20
2.3 Рабочее поле.20
3. Пример работы программы.20
ВЫВОДЫ.23
СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ24
ВВЕДЕНИЕ
Основой алгоритма Ли является процедура нахождения оптимального в смысле некоторого критерия пути между заданными ячейками A и B ДРП при соблюдении ряда условий. Первая часть алгоритма моделирует процесс распространения волны из ячейки A по свободным ячейкам ДРП. При распространении волны от элементарной площадки А алгоритм последовательно строит Ф1 (A) - первый, Ф2 (A) - второй,..., Фk (А) - k-й ее фронты. Множество ячеек, входящих в i-е фронты, для всех i<=k называют k-й окрестностью ячейки A - O(k) (А). Если проведение пути возможно, то на каком-то k + 1-м шаге окажется, что ячейка В Є O(k+1)(А). Если в следующий фронт не удается включить ни одной свободной ячейки, т. е. O(k+1) (A) = O(k) (A), то при данных условиях путь провести невозможно. Таким образом эта часть алгоритма определяет возможность проведения пути между ячейками A и В.
Во второй части алгоритма, начиная с ячейки В, по определенным правилам выполняется переход от ячейки k-го фронта к ячейке (k-1)-го фронта до ячейки А. Пройденные ячейки составляют искомый путь.
Условия, которые необходимо выполнить при проведении пути и возможность оценки его оптимальности должны быть заложены в правила, по которым движется фронт волны. Для ячеек дискретного поля устанавливаются отношения соседства. Распространение волны заключается в присваивании ячейкам, соседним с ячейкой предыдущего фронта, значения весовой функции. Вес ячейки k-гo фронта Рk является функцией веса ячейки (k-1)-го фронта. В общем случае к весам предъявляется требование Р(k-1) ≠ Р(k)≠ Р(k+1).
ТЕОРЕТИЧЕСКАЯ ЧАСТЬ
1. Общая постановка задачи трассировки задачи трассировки
Трассировка заключается в определении конкретной геометрии печатного или проводного монтажа, реализующего соединения между элементами схемы. Исходными данными для трассировки явяютcя список цепей, метрические параметры и топологические свойства типовой конструкции и ее элементов и результаты решения задачи размещения, по которым находятся координаты выводов элементов. Формальная постановка задачи трассировки и методы ее решения в значительной степени зависят от вида монтажа (проводной или печатный) и конструктивно-технологических ограничений, определяющих метрические параметры и топологические свойства монтажного пространства.
В типовых конструкциях, начиная с блока и выше, довольно широко используется проводной монтаж, что объясняется высокой трудоемкостью проектирования и сложностью изготовления печатного монтажа. Изготовление печатного монтажа усложняется с увеличением размеров коммутационных плат, а надежность его падает. Проводной монтаж может осуществляться по прямым, соединяющим выводы элементов, или с помощью жгутов, которые прокладывают в специальных каналах. Основные ограничения - количество проводников, которые можно подсоединять к одному выводу (обычно не более трех), и число проводов в каждом жгуте - пропускная способность канала.
2. Трассировка проводного монтажа.
Заключается в определении порядка соединения выводов в соответствии с принципиальной электрической схемой и с учетом заданных ограничений. Критерием качества, как правило, является минимум суммарной длины соединений. Нахождение порядка соединения выводов элементов внутри цепи сводится к задаче построения на фиксированных вершинах минимального покрывающего или связывающего дерева. Будем использовать модель схемы в виде графа, в котором выводам элементов сопоставлены вершины я на этих вершинах строится полный подграф. Таким образом, каждая цепь представляется отдельной компонентой связности. Необходимо построить минимальные покрывающие деревья на тех компонентах связности, число вершин в которых больше двух. Напомним, что в результате размещения элементов определены координаты их выводов в соответствующей метрике, т. е. вершины компонент связности отображены в граф решетки монтажного пространства.
Трассировка при печатном монтаже. В монтажном пространстве, представляющем собой совокупность коммутационных плоскостей, определены координаты конструктивных элементов и их выводов; заданы метрические параметры и топологические свойства монтажного пространства (ширина проводников и зазоров между ними, координаты и размеры контактных площадок, число слоев МПП и переходы со слоя на слой, координаты и размеры областей, запрещенных для трассировки). .Множество цепей принципиальной схемы разбивает множество В выводов элементов на непересекающиеся подмножества Bi так, что В = {Bi/I= 1,M}, а Вi={bi,k = 1/ki}, где M- число цепей; ki - число контактов, соединяемых i-й цепью.
Необходимо реализовать множество Вi в виде множества Ai таких областей которые удовлетворяли бы следующим требованиям:
1. U Ai Є E - все соединения должны быть выполнены в монтажной области E={Er/r= 1, R}. Здесь R -- число слоев.
* Ai, Ai Є E r (Ai ∩ Aj (i=j) = Ø) - в каждом слое проводники не должны иметь пересечений.
* Ai, A,j Є E r (ρ(Ai, Aj) >=ρ0) - расстояние между проводниками не должно быть меньше допустимого зазора ρ0.
2. d(Ai) >= d0 - ширина проводника не должна бытъ меньше допустимой.
3. ( Ai, k ≡ bi,k) Є Ai - все контакты i-й цепи должны лежать на i-м проводнике.
4. ( Ai Є E r) ( Aj Є E t) (Ai ∩ Aj = Ø V Ai ∩ Aj > Rn); Er, Et Є E - если необходимо выполнить переход со слоя r на слой t, пересечение областей должно иметь размер, достаточный для конструктивной реализации межслойного перехода.
Задача одновременной оптимизации всех соединений пока не решена, поэтому трассировка сводится к последовательному построению бесперекрестного леca, каждое дерево которого реализует соответствующую электрическую цепь, и определению конфигурации соединения. Система покрывающих деревьев должна быть размещена в монтажном пространстве типовой конструкции, заданном своей математической моделью .
Трассировка печатных соединений предполагает выполнение следующих этанов :
1. Определение порядка соединения выводов внутри цени. 2. Распределение соединений но слоям печатной платы. 3. Нахождение последовательности проведения соединений в каждом слое.
4. Получение конфигурации проводников.
При решении задачи трассировки используются следующие основные критерии:
1. Минимум суммарной длины всех проводников.
2. Минимум числа их пересечений.
3. Минимум изгибов проводников.
4. Минимум числа слоев МПП и переходов со слоя на слой.
5. Минимальная длина параллельных участков соседних проводников.
6. Равномерное распределение проводников но монтажной области.
Критерий 1 приводит к уменьшению задержки распространения сигналов по линиям связи, критерии 2, 3 и 4 повышают надежность и технологичность печатной платы, критерии 5 и 6 увеличивают помехоустойчивость конструктивной реализации схемы и вероятность проведения всех трасс. Указанные критерии не удается объединить в обобщенный показатель качества, поэтому на каждом этапе трассировки для конкретной технологии учитывается один наиболее важный критерий или указывается их приоритет.
Определение порядка соединения выводов внутри цепи. Задача сводится к построению минимального связывающего дерева. При печатном монтаже соединения можно выполнять не только по выводам, но и в любой точке проводника. Поэтому построение минимального связывающего дерева формулируется как задача Штейнера: к множеству Р = { рi/i = 1,n } основных добавить множество Q = {qj/j = 1,m } дополнительных точек и построить покрывающее дерево минимальной длины. Здесь множество Р основных точек сопоставлено выводам цепи, а дополнительные точки представляют собой места соединений тина проводник - проводник. При определении положения дополнительных точек можно рассматривать только узлы координатной решетки, построенной па n заданных точках. Тогда число таких точек |Q|<= п - 2. Метод точного решения задачи Штейнера для реальных цепей требует больших затрат машинного времени.
Распределение соединений по слоям. В результате выполнения первого этана трассировки электрическая цепь представляется минимальным покрывающим деревом, являющимся плоским графом. Однако совокупность минимальных деревьев (лес) может иметь пересечения между ребрами, принадлежащими разным деревьям, так как последние строятся на фиксированных вершинах и существуют ограничения на размер монтажного поля, ширину проводников и зазор между ними. В то же время в каждом слое печатные проводники не должны пересекаться.
При ортогональной трассировке возможно распределение соединений но двум слоям. Каждая цепь представляется в виде ортогонального покрывающего дерева, вертикальные ветви которого проводятся в одном слое, а горизонтальные - в другом. В узлах дерева необходимо делать межслойные переходы. Количество переходов оказывается весьма большим, что ухудшает механические параметры печатной платы и снижает надежность схемы.
При трассировке по произвольным направлениям может быть поставлена задача разбиения графа схемы на минимальное количество плоских суграфов или подграфов, каждый из которых реализуется в своем слое. Основная трудность при такой постановке заключается в построении модели схемы, точно отображающей связность элементов и их топологические свойства.
Распределение соединений по слоям может быть сформулировано как задача правильной раскраски вершин графа пересечений . Предполагаем, что соединение полностью выполняется на одном слое. При ортогональной трассировке на вершинах каждой цепи строится минимальный охватывающий прямоугольник. Считается, что два соединения пересекаются, если перекрываются соответствующие им прямоугольники.
При представлении цепи минимальным покрывающим деревом необходимо определять, пересекается ли каждая пара ветвей этих деревьев. Для пары ветвей при известных координатах вершин составляются уравнения прямых линий. Исследуя эти уравнения методами аналитической геометрии, определяют возможность пересечения соответствующих соединений.
Вершины графа пересечений сопоставляются соединениям, ребра устанавливают возможность их пересечения. Раскраска вершин графа будет правильной, если никакие смежные вершины не окрашены одним цветом. Минимальное количество цветов, которое необходимо для правильной раскраски, определяет число слоев МПП.
Перекрытие прямоугольников, построенных на вершинах цепей, или пересечение минимальных покрывающих деревьев еще не означает, что соответствующие цепи нельзя протрассировать на одном слое без пересечений.
При учете возможности проведения "конфликтующих" проводников без пересечения за счет огибания, распределение соединений по слоям может быть сделано путем объединения проводников, идущих под некоторым углом друг к другу, в группы. Каждая такая группа затем трассируется в своем слое.
Трассировка цепей выполняется последовательно и каждая проложенная трасса является препятствием для всех непроведенных. В связи сэтим большое значение приобретает задача нахождения последовательности проведения соединений в каждом слое. Сформулируем условия отсутствия пересечений двух ребер и методику определения последовательности их проведения. Расмотрим два ребра u(i,j) и u(k,p). Их уравнения в параметрической форме для ребер u(i,j) и u(k,p) соответственно имеют вид :
t = λ*t(i) + (1- λ)*t(j) t = μ*t(k) + (1 - μ)*t(p)
S = λ*S(i) + (1 - λ)*S(j) S = μ*S(k) + (1 - μ)*S(p)
где λ=((t(k)-t(p))*(S(j)-S(p))-(S(k)-S(p))*(t(j)-t(p))/((t(k)-t(p))*(S(j)-S(i))-(S(k)-S(p))*(t(j)-t(i));
μ=((t(j)-t(p))*(S(j)-S(i))-(S(j)-S(p))*(t(j)-t(i))/((t(k)-t(p))*(S(j)-S(i))-(S(k)-S(p))*(t(j)-t(i));
Ребра пересекаются, если
0 <= λ <= 1, 0 <= μ <=1.
На oсновании этого условия определяется список пересекающихся ребер. Непересекающиеся ребра можно трассировать в произвольном порядке. Для определения последовательности проведения пересекающихся ребер составляют уравнения удлинения при огибании, считая, что огибающий пpoводник может проходить сколь угодно близко от вершины. Уравнения составляются для всех пар пересекающихся ребер. Для каждого ребра подсчитывается число oгибаний и удлинение. Список ребер ранжируется в порядке возрастания числа огибаний. Если у некоторыx групп ребер число oгибаний одинаково, то первыми проводятся ребра с меньшим удлинением.
Так как пересечение pасcмaтpивается только для пары ребер, необходимо дополнительно проверять отсутствие пересечений с другими близлежащими ребрами. В заключение отметим, что при выполнении соединения полностью в oдном слое возрастает средняя длина проводников за счет огибаний
3. Волновой алгоритм решения задачи трассировки и трассировка в каналах
После выполнения первых трех этапов трассировки множество точек каждой цени разбито на подмножества пар точек и определен порядок их соединения. При использовании модели монтажного пространства построение отрезка печатного проводника, соединяющего очередную пару точек, сводится к нахождению кратчайшего пути между вершинами графа монтажного пространства, которые сопоставлены этим точкам цепи.
Большинство алгоритмов построения конфигурации печатных проводников используют идеи волнового алгоритма Ли, который представляет собой процедуру нахождения кратчайшего пути в графе. Рассмотрим основные положения метода, используя для наглядности иллюстрации дискретное рабочее поде (ДРП). В работе Ли плоскость монтажа разбивается на элементарные квадраты со стороной, равной расстоянию между осями соседних печатных проводников. При использовании ДРП для описания алгоритма Ли включение элементарной ячейки в путь означает проведение печатного проводника так, как это показано на рис.1, т. е. считаем, что основная координатная сетка смещена на h/2, чтобы пути следовали из ячейки в ячейку, а не по координатным линиям ДРН. На каждом шаге алгоритма некоторые ячейки являются занятыми, к ним относятся ячейки, попадающие в области, запрещенные для трассировки: краевые поля монтажной платы, зоны размещения элементов и их выводов, ранее проведенные проводники.
h
Рис. 1. Соответствие ячейки ДРП основной координатной сетке.
Основой алгоритма Ли является процедура нахождения оптимального в смысле некоторого критерия пути между заданными ячейками A и B ДРП при соблюдении ряда условий. Первая часть алгоритма моделирует процесс распространения волны из ячейки A по свободным ячейкам ДРП. При распространении волны от элементарной площадки А алгоритм последовательно строит Ф1 (A) - первый, Ф2 (A) - второй,..., Фk (А) - k-й ее фронты. Множество ячеек, входящих в i-е фронты, для всех i<=k называют k-й окрестностью ячейки A - O(k) (А). Если проведение пути возможно, то на каком-то k + 1-м шаге окажется, что ячейка В Є O(k+1)(А). Если в следующий фронт не удается включить ни одной свободной ячейки, т. е. O(k+1) (A) = O(k) (A), то при данных условиях путь провести невозможно. Таким образом эта часть алгоритма определяет возможность проведения пути между ячейками A и В.
Во второй части алгоритма, начиная с ячейки В, по определенным правилам выполняется переход от ячейки k-го фронта к ячейке (k-1)-го фронта до ячейки А. Пройденные ячейки составляют искомый путь.
Условия, которые необходимо выполнить при проведении пути и возможность оценки его оптимальности должны быть заложены в правила, по которым движется фронт волны. Для ячеек дискретного поля устанавливаются отношения соседства. Распространение волны заключается в присваивании ячейкам, соседним с ячейкой предыдущего фронта, значения весовой функции. Вес ячейки k-гo фронта Рk является функцией веса ячейки (k-1)-го фронта. В общем случае к весам предъявляется требование Р(k-1) ≠ Р(k)≠ Р(k+1).
В большинстве модификаций алгоритма Ли на веса накладывается ограничение Р(k)>P(k-1). В этом случае проведение пути заключается в переходе от ячейки В к ячейке A таким образом, чтобы значение P(k) монотонно убывало. При этом возможен вариант, при котором несколько ячеек, соседних данной, имеют одинаковый вес. Для однозначности выбора при учете критерия минимума изгибов проводника следует сохранять направление движения. Если приходится делать поворот, учитывается заранее заданный порядок предпочтительных направлений, например вверх, вправо, вниз, влево.
Рассмотрим случай, когда соседними к данной являются ячейки, имеющие с ней общее ребро, а вес ячейки k-го фронта P(k)=P(k-1)+1 т. е. равен расстоянию k-й ячейки от исходной А в ортогональной метрике. Волна распространяется из ячейки А, вес которой считаем равным нулю. Фронт волны доходит до ячейки В. Например в ходе построения пути из ячейки с весом 11 можно перейти в три соседние ячейки с весом 10. Здесь переход осуществляется, сохраняя направление движения. Аналогично происходит переход из ячейки с весом 10. У ячейки с весом 9 есть две соседние ячейки с весом 8. Если приходится изменять направление движения, переход выполняется по предпочтительному направлению. Так как алгоритм Ли представляет собой алгоритм нахождения кратчайшего пути в графе, он легко распространяется на многослойный печатный монтаж при использовании модели в виде графа монтажного пространства. При наличии ограничений на переходы со слоя на слой можно увеличить вес ребра, соединяющего две смежные вершины на соседних слоях, по сравнению с весом ребра, соединяющего смежные вершины одного слоя.
В общем случае весовая функция или критерий качества пути может зависеть от параметров, учитывающих длину пути, число переходов со слоя на слой, степень близости пути к другим и т. д., например в виде аддитивной функции P(k)=a(i)*pi(k), где a(i)-весовой коэффициент, учитывающий важность i-го параметра; рi(k) - значение учитываемого параметра.
Однако усложнение функции веса увеличивает объем информации на одну ячейку ДРП и время работы первой части алгоритма. Кроме того, не представляется возможным строго обосновать выбор значений весовых коэффициентов а(i).
При практической реализации волнового алгоритма важная проблема - сокращение объема памяти, необходимой для запоминания весов ячеек. При вычислении весов ячеек по указанной выше формуле ячейка может быть в следующих состояниях: свободна, занята или имеет вес от единицы до L, где L - максимально возможная длина пути, определяемая как количество составляющих его ячеек ДРП. Необходимое для запоминания состояния одной ячейки ДРП число разрядов памяти: N = log2 (L + 2).
Наиболее эффективными способами кодирования состояния ячеек ДРП являются метод путевых координат, кодирование по модулю 3 и использование базовой последовательности 1,1,2,2,1,1,2,2, предложенной Акерсом.
При выборе последовательности ячеек на этапе построения пути по методу путевых координат для каждой ячейки, начиная с В, в случае соседства по ребрам достаточно знать, от какой соседней ячейки в нее пришла волна: сверху, слева, снизу, справа (,,,). Таким образом, ячейка может иметь следующие признаки: свободна, занята или одну из путевых координат ,,,. Следовательно, число разрядов на кодирование состояния ячеек N=log2(6)=3. Если в данную ячейку волна приходит из нескольких соседних, то присвоение путевых координат выполняется по заранее заданному правилу приоритетов. При проведении пути достаточно переходить по путевым координатам из ячейки В в ячейку A
Кодирование по модулю 3 базируется на основном требовании к весам: Р(k-1) ≠ Р(k)≠ Р(k+1). Ячейкам, включаемым в последовательные фронты, можно присваивать не сами веса, а их значения по модулю 3, т.е. 1,2,3, 1,2,3, ... Количество разрядов на кодирование состояния ячеек N=log2(5)=3. Проведение пути заключается в отслеживании отметок. Если ячейка имеет несколько соседних с одинаковыми отметками, то используется правило приоритетных направлений. Для определения последовательности ячеек, составляющих путь, достаточно, чтобы при распространении волны ячейкам присваивались значения отметок из заданной последовательности, в которой каждый член имеет разных соседей слева и справа. В методе Акерса такой последовательностью является 1,1,2,2,1,1,2,2, ... При построении пути находят ячейки, входящие в заданную последовательность. В методе Акерса кoличество разрядов памяти на ячейку ДРП N=lof2(4)=2.Если построение последовательности возможно по нескольким направлениям, то выбор осуществляют по приоритетам. Волновой алгоритм характеризуется высокой эффективностью нахождения пути за счет исследования всех свободных ячеек ДРП, но требует значительного времени на распространение волны. В связи с этим используются различные методы ускорения выполнения первого этапа алгоритма. Одним из них является выбор начальной точки. При выборе в качестве источника распространения волны площадки, максимально удаленной от центра платы, просматривается меньшee число свободных ячеек ДРП. Это становится очевидным по мере роста числа протрассированных цепей.
Более эффективен метод встречной волны. Выигрыш во времени пропорционален отношению числа исследуемых ячеек при одновременном распространении волны и при распространении волны из одного источника. При непрерывной модели окрестности волны на свободном поле ДРП отношение исследуемых площадей M=π*r*r/(2*π(r/2)^2)=2. Для реальных состоянии ДРП выигрыш во времени может отличаться, однако в среднем оценка является объективной. Использование данной идеи приводит к усложнению алгоритма.
Поле распространения волны можно уменьшить, ограничивая его прямоугольником, внутри которого находятся соединяемые площадки. Начальная площадь прямоугольника обычно на 10-20% больше площади прямоугольника, проходящего через эти площадки. Если соединение найти не удалось, то границы прямоугольника расширяются. Данный метод обладает большей эффективностью ускорения работы алгоритма но сравнению с вышеописанными.
Волновой алгоритм можно использовать при различных стратегиях построения цепей. Выполнение первых трех этапов задачи трассировки подразумевает переход к построению следующей цепи после получения конфигурации текущей или установления невозможности этого. Вследствие того, что в цепь могут входить как длинные соединения, так и короткие, при такой стратегии будет нарушен желательный порядок проведения соединений от коротких к длинным. После длинных отрезков одной цепи могут строиться более короткие первые отрезки следующей цепи. Чтобы избежать этого, проводят сначала соединения, стоящие первыми в списках всей цепей, затем вторые и т. д. Данный подход будет более корректным, если после распределения соединений по слоям определить порядок проведения отрезков по всем цепям каждого слоя.
Одна из модификаций алгоритма Ли позволяет исключить этап определения порядка соединения выводов внутри каждой цепи. В этом алгоритме используется метод встречной волны. Из n элементарных площадок, сопоставленных контактам цепи, одновременно распространяются волны до тех пор, пока не встретятся два фронта. Выполняется вторая часть алгоритма Ли. т. е. строится фрагмент цепи, соединяющий два контакта. Снова распространяются волны, но уже из п - 1 источников. Алгоритм соединяет две ближайшие ячейки или связанные системы ячеек с учетом преград в виде ранее проведенных соединений.
СПЕЦИАЛЬНАЯ ЧАСТЬ. ОПИСАНИЕ РАЗРАБОТАННОГО ПРОГРАММНОГО СРЕДСТВА
1. Назначение и особенности программы
Программа реализует исполнение волнового алгоритма трассировки при печатном монтаже. В качестве исходных данных она предполагает ввод пользователем принципиальной схемы, задающей исходный набор элементов и связей между ними а так же ширину проводников и зазоров между ними. Решение задачи заключается в применении к этой схеме волнового алгоритма трассировки, то есть в определении конкретной геометрии печатного или проводного монтажа, реализующего соединения между элементами схемы.
Программа требовательна к оборудованию по следующим причинам
* т.к. в программе реализован волновой алгоритм то много времени требуется на распространение волны, из-за этого возникает требование к производительности
* программе требуется значительный объем оперативной памяти для хранения весов ячеек ДРП. Программа предоставляет пользователю следующие возможности :
1. Ввод и размещение микросхем семи видов
2. Задание связей между выводами микросхем путем их построения
3. Редактирование схемы
4. Введение топологических свойств монтажного пространства
* ширина проводников от1 до 4
* зазор между проводниками от 1 до 6
5. Сохранение и открытие схемы и результата трассировки если он есть
6. Трассировка печатного монтажа алгоритмом волновой трассировки Ли
7. Распределение соединений по слоям .
8. Просмотр результата трассировки
* все слои сразу или по отдельности
2. Руководство пользователя
(рис. 1) Внешний вид программы.
После запуска программы появится приложение, показанное на (рис.1). Здесь можно выделить пять основных блоков:
1. Главное меню;
2. Панель инструментов;
3. Рабочее поле;
4. 5. Полосы прокрутки;
5. Информационная панель;
Теперь остановимся на каждом из них поподробнее.
2.1 Главное меню
Главное меню состоит из трех пунктов:
1. Файл;
2. Трассировка;
3. Помощь;
Меню "Файл" состоит из пяти пунктов.
1. Новый. Создание новой схемы для трассировки.
2. Сохранить. Сохранение текущей схемы на носитель информации.
3. Загрузить. Загрузка готовой схемы с носитель.
4. База. Загрузка базы элементов.
5. Выход. Завершение работы программы.
6. Экспорт в Clipboard. Копирование изображение платы в буфер обмена.
Меню "Трассировка" состоит из двух пунктов.
1. Трассировать. Запуск волнового алгоритма трассировки печатного монтажа.
2. Параметры. Определение параметров трассировки: * Ширина проводника;
* Зазор между проводниками:
* Качество трассировки (0-2000). Чем больше число, тем больше качество трассировки.
2.2 Панель инструментов.
Панель инструментов состоит из пяти элементов (слева направо):
1. Редактировать. В этом режиме пользователь может передвигать, удалять (щелчок правой кнопкой мыши), и указывать элементы схемы.
2. Поместить элемент. С помощью этого элемента пользователь помещает выбранный справа в ComboBox один из семи элементов на схему.
3. Провести цепь. Проведение соединений между элементами схемы.
4. Поместить границу. С помощью этого инструмента пользователь указывает границу и размер схемы, а так же запрещенные для трассировки секторы.
5. ComboBox. Содержит список пяти элементов.
2.3 Рабочее поле.
Рабочее поле предназначено для размещения и редактирования схемы печатной планы с помощью панели инструментов.
3. Пример работы программы.
Запускаем программу. Если каталог с программой был перенесен в другое место, то следует указать нахождение базы элементов (файл DIPbase.ugo) с помощью меню Файл->База->Микросхемы.
Далее можно приступать к рисованию схемы 500х300. Для этого сначала определим область и размер печатной платы с помощью инструмента "Поместить границу". Растягиваем рамку до нужных размеров. Потом границу можно подредактировать с помощью инструмента "Редактировать". Далее с помощью инструмента "Поместить элемент" размещаем элементы по площади платы. Для редактирования можно опять воспользоваться вышеуказанным инструментом. Расстановка элементов на свои места упрощена за счет привязки к сетке. Затем с помощью инструмента "Провести цепь", соединяем элементы. Для наглядности проведем две зоны, запрещенные для трассировки. Получилась следующая схема:
Далее можно приступать к трассировке. Но прежде следует выделить границу (щелкнуть по ней мышкой в режиме редактирование) в которой будет производиться трассировка см. рис. Затем открываем меню Трассировка->Параметры и задаем следующие параметры трассировки.
Далее Трассировка->Трассировать. Данная программа при трассировке руководствуется следующими критериями:
1. Наименьшее число слоев печатной платы
2. В каждом слое наименьшая суммарная длинна проводников (при определенном порядке трассировки проводников)
Получились следующие результаты:
В этом окне показаны все слои, для просмотра каждого по отдельности следует воспользоваться стрелками вперед и назад см. рис.
ВЫВОДЫ.
Как видно по результату, полученный печатный монтаж не является оптимальным и в разбиении по слоям и в трассировке проводников в одном слое с минимальной суммарной длиной проводников, это объясняется следующим: данная программа реализует задачу трассировки проводов упорядоченных по возрастанию их длинны и если провод нельзя провести в данном слое то он переносится в другой, таким образом, для получения оптимальной схемы, необходимо сначала решить задачу распределения проводников по слоям и порядок их трассировки и уже затем, используя решения этих задач применять программу трассировки.
СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ
1. Савельев А.Я. Овчинников В.А. "Конструирование ЭВМ и систем", М., 1989 г.
2. Анисимов Б.В. Савельев А.Я. "Основы конструирования и производства ЭВМ", М., 1972 г.
3. Елманова Н.З., Кошель С.П. Введение в Borland C++ Builder. Москва, ДИАЛОГ - МИФИ, 1997г. ПРИЛОЖЕНИЕ 1. ЛИСТИНГ ПРОГРАММЫ
#include <vcl.h>
#pragma hdrstop
#include "UGOUnit.h"
//---------------------------------------------------------------------------
void sLabel::Draw(TCanvas *c,int dx,int dy,TColor Back,TColor PenCl)
{
int OldCt=c->Brush->Style;
c->Brush->Color=Back;
if(!Trans)
{
c->Brush->Style=bsSolid;
c->Brush->Color=Back;
//c->FillRect(Rect(Area.x+dx,Area.y+dy,Area.x+Area.w+dx,Area.y+Area.h+dy));
}
else
c->Brush->Style=bsClear;
TColor OldCl=c->Font->Color;
c->Font->Color=PenCl;
c->TextOut(Area.x+dx+2,Area.y+dy+2,Text);
c->Font->Color=OldCl;
c->Brush->Style=OldCt;
}
//---------------------------------------------------------------------------
void sLabel::DrawRect(TCanvas *c,int dx,int dy)
{
c->Pen->Style=psDot;
int OldSt=c->Brush->Style;
c->Brush->Style=bsClear;
c->MoveTo(Area.x+dx,Area.y+dy);
c->LineTo(Area.x+Area.w+dx,Area.y+dy);c->LineTo(Area.x+dx+Area.w,Area.y+Area.h+dy);
c->LineTo(Area.x+dx,Area.y+Area.h+dy);c->LineTo(Area.x+dx,Area.y+dy);
c->Pen->Style=psSolid;
c->Brush->Style=OldSt;
}
//---------------------------------------------------------------------------
void TEditField::SetText(sLabel *l)
{//установить текст-по метке
Text=l->Text;
Area=l->Area;
}
//---------------------------------------------------------------------------
void TEditField::Draw(TCanvas *c,int dx,int dy)
{
c->Brush->Style=bsClear;
c->TextOut(Area.x+dx+2,Area.y+dy+2,Text);
c->Rectangle(Area.x+dx,Area.y+dy,Area.x+Area.w+dx,Area.y+Area.h+dy);
c->Brush->Style=bsSolid;
}
//---------------------------------------------------------------------------
void TEditField::DrawRect(TCanvas *c,int dx,int dy)
{
c->Brush->Style=bsClear;
c->Rectangle(Area.x+dx,Area.y+dy,Area.x+Area.w+dx,Area.y+Area.h+dy);
c->Brush->Style=bsSolid;
}
//---------------------------------------------------------------------------
void TEditField::CursXY(int *x,int *y,int dx,int dy)
{//вернуть координаты курсора
*x=Area.x-2+dx+Area.w; *y=Area.y+1+dy;
}
//---------------------------------------------------------------------------
bool TEditField::OnKey(WORD Key,TCanvas *c)
{//реакция на клавишу
if(Key==VK_BACK)
{
Text.SetLength(Text.Length()-1);
Area.w=c->TextWidth(Text)+4;
return false;
}
if((Key==VK_RETURN)||(Key==VK_ESCAPE)){Active=false;return true;}
Text=Text+(char)Key;
Area.w=c->TextWidth(Text)+4;
return false;
}
//---------------------------------------------------------------------------
void TEditField::Move(int X,int Y,Box BoundBox)
{
if((X>0)&&(Y>0)&&(X+Area.w<BoundBox.w)&&(Y+Area.h<BoundBox.h))
{Area.x=X;Area.y=Y;}
}
TPin::TPin(TPin *Old)
{
Fire=false;
PID=Old->PID;ID=Old->ID;IsIn=Old->IsIn;Label=new sLabel;
Label->Text=Old->Label->Text; Label->Area.Copy(Old->Label->Area);
Len=Old->Len;Type=Old->Type;UgoID=Old->UgoID;y=Old->y; Label->Trans=false;
Colors[0]=Old->Colors[0]; Colors[1]=Old->Colors[1];
Colors[2]=Old->Colors[2]; Colors[3]=Old->Colors[3];
}
//---------------------------------------------------------------------------
void TPin::Draw(TCanvas *c,int dx,int dy,bool Rect,char DrawingStyle)
{
TBrushStyle OldSt=c->Brush->Style;
c->Brush->Style=bsClear;
//int tx,ty;
//ty=-c->TextHeight(Label->Text);
//if(ty==0)ty=-12;
//ty+=(y-1);
//if(IsIn)tx=-Len;
//else tx=3;
//вывод текста
//Label->Area.x=tx+dx; Label->Area.y=ty+dy;
//if(Fire)Label->Draw(c,0,0,clRed,Colors[2]); //подсветить красным
//else Label->Draw(c,0,0,Colors[3],Colors[2]);//закрасить цветом заливки(cl[3])
TColor OldCl=c->Pen->Color;//сохранение цвета
c->Pen->Color=Colors[1];//цвет линий
if(Rect)Label->DrawRect(c,0,0);
//линия - окружность
if(IsIn) {c->Ellipse(dx-Len-4,dy+y-4,dx-Len+4,dy+y+4);}
else {c->Ellipse(dx+Len-4,dy+y-4,dx+Len+4,dy+y+4);}
//тип ноги
/*if(Type==INVERSE_PIN)
{
if(DrawingStyle==ISO_STYLE)c->Ellipse(dx-3,dy+y-3,dx+3,dy+y+3);
else
{
if(IsIn){c->MoveTo(dx-6,dy+y);c->LineTo(dx-6,dy+y-4);c->LineTo(dx,dy+y);}
else {c->MoveTo(dx,dy+y-4);c->LineTo(dx+6,dy+y);}
}
}
if(Type==FRONT_PIN)
{
if(DrawingStyle==ISO_STYLE)
{
c->MoveTo(dx-3,dy+y+3);
c->LineTo(dx+3,dy+y-3);
}
else
{//треугольник вправо
c->MoveTo(dx-4,dy+y-3);c->LineTo(dx+3,dy+y);
c->LineTo(dx-4,dy+y+3);c->LineTo(dx-4,dy+y-3);
}
}
if(Type==BACK_PIN)
{
if(DrawingStyle==ISO_STYLE)
{
c->MoveTo(dx-3,dy+y-3);
c->LineTo(dx+3,dy+y+3);
}
else
{//треугольник влево
c->MoveTo(dx-4,dy+y);c->LineTo(dx+4,dy+y-3);
c->LineTo(dx+4,dy+y+3);c->LineTo(dx-4,dy+y);
}
} */
c->Pen->Color=OldCl;//восстановление цвета
c->Brush->Style=OldSt;
}
//---------------------------------------------------------------------------
void TPin::SetText(AnsiString txt,TCanvas *c)
{
Label->Text=txt;
Label->Area.w=c->TextWidth(txt);
Label->Area.h=c->TextHeight(txt);
if(Label->Area.h<2)Label->Area.h=12;
if(Label->Area.w<2)Label->Area.w=8;
}
//---------------------------------------------------------------------------
bool TPin::IsNear(int X,int Y,int dx,int dy)
{
if(IsIn){if(abs(X-dx+Len)<3)if(abs(Y-dy-y)<3)return true;}
else {if(abs(X-dx-Len)<3)if(abs(Y-dy-y)<3)return true;}
return false;
}
//---------------------------------------------------------------------------
TPin::TPin()
{
Fire=false;
Type=SIMPLE_PIN;
PID=-1;ID=UgoID=-1;y=0;Len=20;IsIn=true;
Label=new sLabel; Label->Trans=false;
Label->Area.w=12;Label->Area.h=12;
Label->Area.x=Label->Area.y=0;
}
//---------------------------------------------------------------------------
void TUGO::Update(TCanvas *c)
{
if(Type==INDC_TYPE)
{//проверить, изменилось ли состояние выводов
if(SetIndState())Draw(c);
return;
}//рисовать весь индикатор
DrawPins(c);//только перерисовать выводы
}
//---------------------------------------------------------------------------
void TUGO::DrawPins(TCanvas *c)
{//рисование выводов
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(p->IsItIn())p->Draw(c,x,y,LAreaSel,DrawingStyle);
else p->Draw(c,x+w,y,LAreaSel,DrawingStyle);
}
}
//---------------------------------------------------------------------------
bool TUGO::SetIndState()
{//установить состояние индикатора
char Mask=1;//one hex letter & mask
char P=0;//состояние выводов
TPin *p;
for(int i=0;i<4;i++)
{
p=(TPin*)Pins->Items[i];
if(p->IsFire())P+=Mask;
Mask=Mask<<1;
}//анализируем выводы
bool Res=(PrevIndicate!=P);
PrevIndicate=P;
return Res;
}
//---------------------------------------------------------------------------
void TUGO::Draw(TCanvas *c)
{
//сохранение параметров рисования
TPenStyle OldSt=c->Pen->Style;
//рисование контура
c->Brush->Style=bsSolid;
c->Brush->Color=Colors[0];//цвет заливки
if(Selected) c->Pen->Style=psDot;
TColor OldCl=c->Pen->Color;
c->Pen->Color=Colors[1];//цвет обводки
c->Pen->Width=2;
c->FillRect(Rect(x,y,x+w,y+h));
//ключ
int ArcX1,ArcX2,ArcH;
ArcX1=x+w/4;ArcX2=x+w*3/4;
ArcH=w/5;
c->Arc(ArcX1,y-ArcH,ArcX2,y+ArcH, ArcX1,y,ArcX2,y);
c->MoveTo(x,y); c->LineTo(ArcX1,y);
c->MoveTo(ArcX2,y); c->LineTo(x+w,y);
c->LineTo(x+w,y+h); c->LineTo(x,y+h);
c->LineTo(x,y);
c->Pen->Width=1;
//разделители
//c->MoveTo(x+LeftS,y);c->LineTo(x+LeftS,y+h);
//c->MoveTo(x+RightS,y);c->LineTo(x+RightS,y+h);
//восстановление параметров рисования
c->Pen->Style=OldSt;
c->Pen->Color=OldCl;
if(Targeting)DrawTargets(c);
//рисование меток со смещением
//для метки, содержащей текст **...*,-меняем на **...*.ID в спец. режиме
OldCl=c->Font->Color;
c->Font->Color=Colors[2];//цвет текста
sLabel *l;
AnsiString Txt;
/*int SubPos;
int SLX;//spec label x
for(int i=0;i<Labels->Count;i++)
{
l=(sLabel*)Labels->Items[i];
if(OutID&&ID>-1)
{
Txt=l->Text;
SubPos=Txt.Pos(",");
if(SubPos>0)
{//вывод спец. текста
Txt.SetLength(SubPos-1);
//выбиваем текст из элемента
c->Brush->Style=bsClear;
SLX=x+(w-c->TextWidth(Txt))/2;
c->TextOut(SLX,y-c->TextHeight(Txt)-1,Txt);
//номер элемента
Txt="DD."; if(ID<100)Txt=Txt+"0";
if(ID<10)Txt=Txt+"0";
Txt=Txt+IntToStr(ID);
SLX=x+(w-c->TextWidth(Txt))/2;
c->TextOut(SLX,y+h+1,Txt);
c->Brush->Style=bsSolid;
}
else l->Draw(c,x,y,Colors[3],Colors[2]);
} else l->Draw(c,x,y,Colors[3],Colors[2]);
if(LAreaSel)l->DrawRect(c,x,y);
}
*/
c->Brush->Style=bsClear;
Txt="DIP";
c->TextOut(x+(w-c->TextWidth(Txt))/2,y+15,Txt);
Txt=IntToStr(Pins->Count);
c->TextOut(x+(w-c->TextWidth(Txt))/2,y+c->TextHeight(Txt)+18,Txt);
Txt="MS"; if(ID<100)Txt=Txt+"0";
if(ID<10)Txt=Txt+"0";
Txt=Txt+IntToStr(ID+1);
int SLX=x+(w-c->TextWidth(Txt))/2;
c->TextOut(SLX,y+h+1,Txt);
c->Brush->Style=bsSolid;
c->Font->Color=OldCl;//восстановление цвета текста
DrawPins(c);
//рисование разделителей
OldCl=c->Pen->Color;
c->Pen->Color=Colors[1];//цвет обводки
if((StCount)&&(LeftS>3))
{
for(int i=0;i<StCount;i++)
{ c->MoveTo(x,Sts[i]+y);c->LineTo(x+LeftS,Sts[i]+y); }
}
c->Pen->Color=OldCl;//восстановление цвета обводки
if(Type==INDC_TYPE)
{//рисование cегментов
short C;
char P=PrevIndicate;
if(P==0)C=0x3F;
if(P==1)C=0x06;
if(P==2)C=0x5B;
if(P==3)C=0x4F;
if(P==4)C=0x66;
if(P==5)C=0x6D;
if(P==6)C=0x7D;
if(P==7)C=0x07;
if(P==8)C=0x7F;
if(P==9)C=0x6F;
if(P==10)C=0x77;
if(P==11)C=0x7C;
if(P==12)C=0x39;
if(P==13)C=0x5E;
if(P==14)C=0x79;
if(P==15)C=0x71;
//рисование тени
TColor OldC=c->Pen->Color;//сохранение цвета пера
c->Pen->Color=Colors[1];
c->Brush->Color=Colors[0];
c->Rectangle(x+6,y+6,x+w-6,y+h-6);
c->MoveTo(x+6,y+h/2); c->LineTo(x+w-6,y+h/2);
//рисование знаков
c->Pen->Width=3;
c->Pen->Color=clRed;
if(C&1){c->MoveTo(x+6,y+6);c->LineTo(x+w-6,y+6);}
if(C&2){c->MoveTo(x+w-6,y+6);c->LineTo(x+w-6,y+h/2);}
if(C&4){c->MoveTo(x+w-6,y+h/2);c->LineTo(x+w-6,y+h-6);}
if(C&8){c->MoveTo(x+w-6,y+h-6);c->LineTo(x+6,y+h-6);}
if(C&16){c->MoveTo(x+6,y+h-6);c->LineTo(x+6,y+h/2);}
if(C&32){c->MoveTo(x+6,y+h/2);c->LineTo(x+6,y+6);}
if(C&64){c->MoveTo(x+6,y+h/2);c->LineTo(x+w-6,y+h/2);}
c->Pen->Color=OldC;//восстановление цвета пера
c->Pen->Width=1;
}
}
//---------------------------------------------------------------------------
TUGO::TUGO()
{
DrawingStyle=ANSI_STYLE;
Description=new TList;
PrevIndicate=0;
Type=SOME_TYPE;
OutID=false;
NetID=-1;
Name="nondefined";
ID=-1;
Sts=0; StCount=0;
MinH=MinW=25;MaxH=250;MaxW=150;
LAreaSel=true;
SelectedLabel=-1; PinSelLabel=-1;
SelectedPin=-1;
Selected=false;
x=y=50;
w=50;h=100;
LeftS=0;RightS=w-1;
Labels=new TList;
Pins=new TList;
Targeting=false;
Colors[0]=clWhite; Colors[1]=clBlack; Colors[2]=clBlack; Colors[3]=clBtnFace;
}
//---------------------------------------------------------------------------
TUGO::~TUGO()
{
delete []Sts;
sLabel *l;
for(int i=0;i<Labels->Count;i++)
{
l=(sLabel*)Labels->Items[i];
delete l;l=0;
}
delete Labels; Labels=0;
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
delete p;p=0;
}
delete Pins;Pins=0;
AnsiString *txt;
for(int i=0;i<Description->Count;i++)
{
txt=(AnsiString*)Description->Items[i];
delete txt;txt=0;
}
delete Description; Description=0;
}
//---------------------------------------------------------------------------
void TUGO::SetSelLabel(AnsiString Txt,TCanvas *c)
{
if(SelectedLabel==-1)return;
sLabel *Label=(sLabel*)Labels->Items[SelectedLabel];
Label->Text=Txt;
Label->Area.w=c->TextWidth(Txt)+4;
Label->Area.h=c->TextHeight(Txt)+2;
}
//---------------------------------------------------------------------------
void TUGO::SetID(int id)
{
ID=id;
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
p->SetUgoID(id);
}
}
//---------------------------------------------------------------------------
void TUGO::SetSelLabel(sLabel *l,TCanvas *c)
{
if(SelectedLabel!=-1)
{
sLabel *L=(sLabel*)Labels->Items[SelectedLabel];
L->Area.x=l->Area.x;L->Area.y=l->Area.y;
L->Area.h=l->Area.h;L->Area.w=l->Area.w;
L->Text=l->Text;
if(Targeting)
{//snap
Box SA;//Snap Area
SA.x=LeftS+5;SA.w=RightS-5-SA.x;
if(SA.w<18){SA.x=3;SA.w=w-3-SA.x;}
if(SA.w>32)
{ SA.x=w/2-16;SA.w=w/2+16-SA.x; }
SA.y=4; SA.h=13;
if(SA.IsIn(L->Area.x,L->Area.y))
{
int tx,ty=3;
if((RightS-LeftS)>=(c->TextWidth(L->Text)+6))
tx=(RightS+LeftS)/2-c->TextWidth(L->Text)/2;
else tx=w/2-c->TextWidth(L->Text)/2;
L->Area.x=tx; L->Area.y=ty;
return;
}
//пробная привязка к ногам
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(p->IsItIn()){ SA.x=3;SA.w=13-SA.x; }
else { SA.x=w-13;SA.w=w-3-SA.x;}
SA.y=p->GetY()-6; if(SA.y<3)SA.y=3;
if((SA.y+17)>h)SA.y=h-17; SA.h=12;
if( (p->IsItIn()&&SA.IsIn(L->Area.x,L->Area.y))
||(!p->IsItIn()&&SA.IsIn(L->Area.x+L->Area.w,L->Area.y)) )
{//snap
if(p->IsItIn())L->Area.x=3;
else L->Area.x=w-5-c->TextWidth(L->Text);
L->Area.y=p->GetY()-c->TextHeight(L->Text)/2;
if(L->Area.y<3)L->Area.y=3;
if(L->Area.y>(h-c->TextHeight(L->Text)-3))
L->Area.y=h-c->TextHeight(L->Text)-3;
return;
}
}//конец цикла по ногам
}//end of "If Targeting..."
}//end of main If
if(PinSelLabel!=-1)
{
TPin *p=(TPin*)Pins->Items[PinSelLabel];
p->SetText(l->Text,c);
}
}
//---------------------------------------------------------------------------
AnsiString TUGO::GetLabel()
{
if(SelectedLabel==-1)return "";
sLabel *L=(sLabel*)Labels->Items[SelectedLabel];
return L->Text;
}
//---------------------------------------------------------------------------
bool TUGO::IsOnText(int X,int Y)
{
sLabel *l;
SelectedLabel=-1; PinSelLabel=-1;
for(int i=0;i<Labels->Count;i++)
{
l=(sLabel*)Labels->Items[i];
if(l->Area.IsIn(X-x,Y-y))
{SelectedLabel=i;return true;}
}
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(p->IsOnText(X,Y)){PinSelLabel=i;return true;}
}
return false;
}
//---------------------------------------------------------------------------
void TUGO::AddLabel(int X,int Y)
{//добавить пустую метку
//проверяем попадание
int lx=X-x+15,ly=Y-y+15;
if((lx>=w)||(ly>=h))return;
sLabel *New=new sLabel;
New->Trans=true;
New->Area.x=X-x; New->Area.y=Y-y;
New->Area.h=New->Area.w=15;
Labels->Add(New);
}
//---------------------------------------------------------------------------
sLabel *TUGO::GetSelected()
{
if(SelectedLabel!=-1) return (sLabel*)Labels->Items[SelectedLabel];
if(PinSelLabel!=-1)
{
TPin *p=(TPin*)Pins->Items[PinSelLabel];
return p->GetLabel();
}
return 0;
}
//---------------------------------------------------------------------------
char TUGO::NearSr(int X,int Y)
{//рядом с разделителем
if((X>=x)&&(X<=(x+w))&&(Y>=y)&&(Y<=(y+h)))
{
if(abs(X-x-LeftS)<3)return 0;
if(abs(X-x-RightS)<3)return 1;
}
return -1;
}
//---------------------------------------------------------------------------
void TUGO::MoveSr(char sr,int X)
{//движение разделителя
X-=x;
if((X<0)||(X>=w))return;
if(sr==0){if(X<RightS)LeftS=X;}
if(sr==1){if(X>LeftS)RightS=X;}
}
//---------------------------------------------------------------------------
bool TUGO::NearCorner(int X,int Y)
{//для изменения размеров
if(abs(X-x-w)<4)if(abs(Y-y-h)<4)return true;
return false;
}
//---------------------------------------------------------------------------
bool TUGO::IsIn(int X,int Y)
{
if((X>x)&&(X<(x+w))&&(Y>y)&&(Y<(y+h)))return true;
return false;
}
//---------------------------------------------------------------------------
void TUGO::SetSize(int X,int Y)
{
bool f1=true,f2=true;//флаги, разрешающие растяжку
if(((Y-y)<h)&&((Y-y)>=MinH))
{//проверяем, не сползет ли вывод
TPin *p;
int MaxY=0;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(p->GetY()>MaxY)MaxY=p->GetY();
}
if((MaxY+5)>(Y-y))f2=false;
}
//проверяем, не уйдет ли разделитель
if(StCount>0)
{
for(int i=0;i<StCount;i++)
if((Sts[i]+5)>(Y-y))f2=false;
}
//проверка на положение меток
if(f1||f2)
{
sLabel *l;
int lx,ly;//нижний левый угол метки
for(int i=0;i<Labels->Count;i++)
{
l=(sLabel*)Labels->Items[i];
lx=l->Area.x+l->Area.w;
ly=l->Area.y+l->Area.h;
if(f1&&(lx>(X-x-4)))//метка у правого края
if((X-x)>w)l->Area.x+=X-x-w;//ползет вправо
if(f1&&((X-x)<=lx))//ползет влево
{ if((X-x-l->Area.w-2)>3)l->Area.x=X-x-l->Area.w-2;
else f1=false; }
if(f2&&ly>(Y-y))l->Area.y=(Y-y)-l->Area.h-2;
}
}//end of if (f1...
if(f2)SetH(Y-y);
if(f1)
{
int DR=w-RightS;
SetW(X-x);
if(w<(LeftS+5))LeftS=w-5;
if(LeftS<0)LeftS=0;
if((w-DR)>LeftS)RightS=w-DR;
}
}
//---------------------------------------------------------------------------
void TUGO::AddPin(bool IsIn)
{//добавить вывод
//определение свободного места
int MaxY=0;
TPin *p,*New;
int SideCount=0;//количество выводов на выбранной стороне
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(p->IsItIn()==IsIn)
{ SideCount++; if(p->GetY()>MaxY)MaxY=p->GetY(); }
}
if(SideCount*15>=(h-30))return;//не влезет
//смотрим, влезет ли вывод
New=new TPin;
New->SetIn(IsIn);
if((h-MaxY)>30)
{
New->SetY(MaxY+15);
Pins->Add(New);
return;
}
//попытка "собрать мусор"
int CurY=15;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(p->IsItIn()==IsIn)p->SetY(CurY);
CurY+=15;
}
New->SetY(CurY);
New->SetUgoID(ID);
New->Colors[0]=Colors[0]; New->Colors[1]=Colors[1]; New->Colors[2]=Colors[2];
Pins->Add(New);//определенно добавляем
}
//---------------------------------------------------------------------------
void TUGO::SetColorsScheme(TColor cl0,TColor cl1,TColor cl2,TColor cl3)
{//применить цветовую схему
Colors[0]=cl0;Colors[1]=cl1;Colors[2]=cl2;Colors[3]=cl3;
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
p->Colors[0]=cl0;p->Colors[1]=cl1;p->Colors[2]=cl2;p->Colors[3]=cl3;
}
}
//---------------------------------------------------------------------------
char TUGO::WhatSelect()
{//какая метка выделена -1 no label,0-own,1-pin
if(SelectedLabel!=-1)return LABEL_SELECT;
if(PinSelLabel!=-1)return PIN_SELECT;
return NO_SELECT;
}
//---------------------------------------------------------------------------
bool TUGO::IsNearPin(int X,int Y)
{
SelectedPin=-1;
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(!p->IsItIn())
{
if(X>(x+w))if(p->IsNear(X,Y,x+w,y))
{ SelectedPin=i;return true; }
}
else
{
if(X<x)if(p->IsNear(X,Y,x,y))
{ SelectedPin=i;return true; }
}
}
return false;
}
//---------------------------------------------------------------------------
TPin *TUGO::GetPinByXY(int X,int Y)
{
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(!p->IsItIn())
{
if(X>(x+w))if(p->IsNear(X,Y,x+w,y)) return p;
}
else
{
if(X<x)if(p->IsNear(X,Y,x,y))return p;
}
}
return 0;
}
//---------------------------------------------------------------------------
TPin *TUGO::NearPin(int X,int Y)
{
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(!p->IsItIn())
{ if(X>(x+w))if(p->IsNear(X,Y,x+w,y))return p; }
else
{ if(X<x)if(p->IsNear(X,Y,x,y))return p; }
}
return 0;
}
//---------------------------------------------------------------------------
void TUGO::MoveSelectedPin(int X,int Y)
{
if(SelectedPin==-1)return;
Y-=y; if(Y>(h-5))return; if(Y<5)return;
TPin *p=(TPin*)Pins->Items[SelectedPin];
p->SetY(Y);
}
//---------------------------------------------------------------------------
void TUGO::InvertSelectPin()
{
if(SelectedPin<0)return;
TPin *p=(TPin*)Pins->Items[SelectedPin];
p->ChangeType();
}
//---------------------------------------------------------------------------
void TUGO::AddSt(int X,int Y)
{//добавление разделителя
if((Y>y)&&(Y<(y+h))&&(X>x)&&(X<(x+LeftS)))
{//есть попадание
//не попали ли в существующий
if(StCount>0)
{
for(int i=0;i<StCount;i++)
if(abs(Sts[i]+y-Y)<3)return;
}
StCount++;
int *NewSt=new int[StCount];//промежуточный массив
if(Sts) for(int i=0;i<(StCount-1);i++)NewSt[i]=Sts[i];
NewSt[StCount-1]=Y-y;
if(Sts)delete []Sts;
Sts=NewSt;
}
}
//---------------------------------------------------------------------------
void TUGO::AddSt(int Y)
{
StCount++;
int *NewSt=new int[StCount];//промежуточный массив
if(Sts) for(int i=0;i<(StCount-1);i++)NewSt[i]=Sts[i];
NewSt[StCount-1]=Y;
if(Sts)delete []Sts;
Sts=NewSt;
}
//---------------------------------------------------------------------------
void TUGO::DelSt(int X,int Y)
{//удаление разделителя
if(StCount==0)return;
if((Y>y)&&(Y<(y+h))&&(X>x)&&(X<(x+LeftS)))
{//есть попадание
int DelIndex=-1;
for(int i=0;i<StCount;i++)
if(abs(Sts[i]+y-Y)<3){ DelIndex=i;break; }
if(DelIndex<0)return;
//перераспределение номеров
for(int i=DelIndex;i<(StCount-1);i++)
Sts[i]=Sts[i+1];
StCount--;
int *NewSt=new int[StCount];//промежуточный массив
for(int i=0;i<StCount;i++)NewSt[i]=Sts[i];
delete []Sts; Sts=NewSt;
}
}
//---------------------------------------------------------------------------
bool TUGO::NearLeftSt(int X,int Y)
{
if(StCount==0)return false;
if((Y>y)&&(Y<(y+h))&&(X>x)&&(X<(x+LeftS)))
{//есть попадание
for(int i=0;i<StCount;i++)
if(abs(Sts[i]+y-Y)<3)return true;
}
return false;
}
//---------------------------------------------------------------------------
bool TUGO::DelPin(int X,int Y)
{
if(IsNearPin(X,Y)==false)return false;
TPin *p=(TPin*)Pins->Items[SelectedPin];
delete p;p=0;
Pins->Delete(SelectedPin);
SelectedPin=-1;
SetSeqPinsID();
return true;
}
//---------------------------------------------------------------------------
void TUGO::DrawTargets(TCanvas *c)
{//подсветить места для меток и разделителей
TBrushStyle OldSt=c->Brush->Style;
c->Brush->Style=bsSolid;
c->Brush->Color=clLtGray;
//1. Основная метка
int l,r,t,b;
l=LeftS+5;r=RightS-5;
if((r-l)<18){l=3;r=w-3;}
if((r-l)>32)
{ l=w/2-16;r=w/2+16; }
t=4; b=17;
c->FillRect(Rect(l+x,t+y,r+x,b+y));
//2.Метки у ножек
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(p->IsItIn()){ l=3;r=13; }
else { l=w-13;r=w-3;}
t=p->GetY()-6; if(t<3)t=3; if((t+17)>h)t=h-17;
b=t+12;
c->FillRect(Rect(l+x,t+y,r+x,b+y));
}
//восстановление кисти
c->Brush->Style=OldSt;
c->Brush->Color=Colors[0];
}
//---------------------------------------------------------------------------
bool TUGO::DeleteLabel(int X,int Y)
{
SelectedLabel=-1;
sLabel *l;
for(int i=0;i<Labels->Count;i++)
{
l=(sLabel*)Labels->Items[i];
if(l->Area.IsIn(X-x,Y-y))
{
delete l;l=0;
Labels->Delete(i);
return true;
}
}
return false;
}
//---------------------------------------------------------------------------
void TUGO::SetType(char t)
{
if(t==INDC_TYPE)
if(Pins->Count!=4){ShowMessage("HEX Indicator must have 4 pins.");return;}
Type=t;
}
//---------------------------------------------------------------------------
TUGO::TUGO(TUGO *Old)
{
DrawingStyle=Old->DrawingStyle;
PrevIndicate=0;
Type=Old->Type;
OutID=false;
NetName=Old->NetName;
NetID=Old->NetID;
Labels=new TList;
Pins=new TList;
MinH=MinW=25;MaxH=250;MaxW=150;
Targeting=Old->Targeting;
PinSelLabel=-1;
SelectedLabel=-1;
SelectedPin=-1;
Selected=false;
Name=Old->Name;
LAreaSel=Old->LAreaSel;
LeftS=Old->LeftS;
RightS=Old->RightS;
ID=Old->ID;
x=Old->x;y=Old->y;
w=Old->w;h=Old->h;
//копия разделителей
StCount=Old->StCount;
Sts=new int[StCount];
for(int i=0;i<StCount;i++) Sts[i]=Old->Sts[i];
//копия ножек
TPin *p,*np;
for(int i=0;i<Old->Pins->Count;i++)
{
p=Old->GetPin(i); np=new TPin(p);
Pins->Add(np);
}
//копия меток
sLabel *l,*nl;
for(int i=0;i<Old->Labels->Count;i++)
{
l=Old->GetLabel(i);
nl=new sLabel; nl->Text=l->Text;
nl->Area.Copy(l->Area);
Labels->Add(nl);
}
Description=new TList;
//копия описания
AnsiString *txt;
for(int i=0;i<Old->Description->Count;i++)
{
txt=new AnsiString;
*txt=(*(AnsiString*)Old->Description->Items[i]);
Description->Add(txt);
}
//копия цветов
for(int i=0;i<4;i++)Colors[i]=Old->Colors[i];
}
//---------------------------------------------------------------------------
void TUGO::SetSeqPinsID()
{//установить последовательные ID выводам
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
p->SetID(i);
}
}
//---------------------------------------------------------------------------
TPin *TUGO::GetPinByID(int PinID)
{
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
if(p->GetID()==PinID)return p;
}
return 0;
}
//---------------------------------------------------------------------------
bool TUGO::GetPinXY(int PinID,int &X,int &Y)
{
TPin *p=GetPinByID(PinID);
if(!p)return false;
Y=p->GetY()+y;
if(p->IsItIn())X=x-p->GetLen();
else X=x+w+p->GetLen();
return true;
}
//---------------------------------------------------------------------------
void TUGO::ResetPinLinks()
{//отвязать все выводы
TPin *p;
for(int i=0;i<Pins->Count;i++)
{
p=(TPin*)Pins->Items[i];
p->SetPID(-1);
}
}
#pragma package(smart_init)
Документ
Категория
Рефераты
Просмотров
38
Размер файла
404 Кб
Теги
отчет
1/--страниц
Пожаловаться на содержимое документа