Определение взаимного положения линий

Procedure

Tch_NiK(XCg,YCg,Xg1,Yg1,Xg2,Yg2,Xs,Ys,XTn,YTn,LDk);

­ ¯

параметры ввода вывода

Дуга NOKO в точке S пересекается с прямой NеKе и дугой NвKв. Направление обхода принимают совпадающим с направлением от начальной точки к конечной начального элемента NOKO. По отношению к начальному элементу определяется положение текущих элементов NеKе и NвKв.

Цель – определить траекторию движения по контуру NOS - SNе - NеS - SKв - KвS - SKO и т.д. в бесконечном цикле если не будет назначен конечный элемент. Одновременно можно определить, что элементы SNе и SKв расположены внутри дуги NOKO.

 

Оператор определяет на дуге измерения начальную точку Тn(XTn,YTn) измерения длины дуги измерения и конечную точку Тк(XTк,YTк) до текущих точек Тe и Tb. Одновременно определяется максимальная длина дуги от Tn до Тk. Если длины дуг от Tn до Te и от Tn до Tb меньше максимальной, то точки Те и Tb расположены внутри дуги NOKO, равно как и отрезки SNe, Skb. Если двигаться в направлении ‘обхода’, то первым встретим отрезок SNe, затем - дугу SKb.

Те же отрезки прямой и дуги

Рис. 107 находятся внутри области, ограни-

ченной дугой NOKO.

Направление обхода принимают совпадающим с направлением от начальной точки к конечной элемента NOKO. По отношению к нему определяется положение остальных линий.

 

Если рассматривается внутренняя область, то направление измерений противоположно направлению обхода.

Центр окружности, длины дуг которой подлежат измерению, находится в точке S. S - точка пересечения NOKO c внешним элементом (элементами).

Начальная точка Тn(XTn,YTn) расположена ближе к началу дуги NO нежели Tk(XTk,YTk).

 

begin

if Obhod=1 then Hod:=2 else Hod:=1; {определено направление

измерений ‘Hod’ для внутренней области}

Элемент, по отношению к которому определяется положение других линий, отрезок прямой:

if El=1 then begin

Определим точки пересечения отрезка прямой и окружности:

TekUgol(Xg1, Yg1, Xg2, Yg2,Ug);

OtrDug(Xg1,Yg1,Ug,Xs,Ys,Ri,XP1,YP1,XP2,YP2,P);

{Ri - радиус окружности измерения дуги}

Найдем точки начала(XTn,YTn) и конца(XTk,YTk) измерений:

DlinaL(Xg1,Yg1,XP1,YP1,L1);

DlinaL(Xg1,Yg1,XP2,YP2,L2);

if L1<L2 then begin

XTn:=XP1; YTn:=YP1; XTk:=XP2; YTk:=YP2;

end

else begin

XTn:=XP2; YTn:=YP2; XTk:=XP1; YTk:=YP1;

end;

Выясним принадлежность точки Tk отрезку прямой:

PikOtr(XTk,YTk,Xg1,Yg1,Xg2,Yg2,P);

Определим LDk:

if P=1 then LDk:=180 else LDk:=360;

{Ldk - max угол, при LD<=LDk точка находится внутри области.

Если S совпадает с концом отрезка прямой, LDk=360. В другом

случае LDk=180}

end

Элемент, по отношению к которому определяется положение других линий, дуга:

else begin

 

 

Определим точки пересечения дуги и окружности:

DugDug(XCg,YCg,R,Xs,Ys,Ri,XP1,YP1,XP2,YP2,P);

Определим длины дуг от начальной точки дуги (Xg1,Yg1) до точек пересечения (XP1,YP1), (XP2,YP2):

DlinaD(XСg,YCg,Xg1,Yg1,XP1,YP1,Nag,LD1);

DlinaD(XCg,YCg,Xg1,Yg1,XP2,YP2,Nag,LD2);

Найдем точки начала(XTn,YTn) и конца(XTk,YTk) измерений:

if LD1<LD2 then begin

XTn:=XP1; YTn:=YP1; XTk:=XP2; YTk:=YP2;

end

else begin

XTn:=XP2; YTn:=YP2; XTk:=XP1; YTk:=YP1;

end;

Определим LDk:

DlinaD(Xs,Ys,XTn,YTn,XTk,YTk,Hod,LDk);

end;

end;

 

Определение отрезков прямых внутри области

 

Если отрезок не имеет точек пересечения с линиями границы области, но одна его точка находится внутри области, то он расположен внутри области. Такой отрезок следует записать в файл отрезков внутри области.

Если отрезок имеет точки пересечения с линиями границы области, то часть его расположена внутри области (рис.108). Чтобы выделить эту часть отрезка, опреде-

Рис. 108 лим в любой последовательности точки пересечения S1, S2 и запишем вместе с линиями области в файл с сортировкой строк файла по возрастанию L, где L- расстояние от начальной точки отрезка до точки пересечения.

Далее следует выяснить принадлежность области каждого отрезка, расположенного между точками пересечения.

 

Оператор записи отрезка прямой в текущий файл:

Procedure Box_Otr;

var P, Ps :byte;

 

 

begin

Ps:=0; {счетчик записей точек пересечения}

Repeat

Читаем файл линий границ выделенной области с 1-ой строки:

SledLine( g, 1, Nag, Xg1, Yg1, Xg2, Yg2, XCg, YCg ),

TekUgol(Xg1, Yg1, Xg2, Yg2,Ug);

Определяем точку пересечения отрезка прямой чертежа

(Xm1,Ym1,Xm2,Ym2) с линией области:

DwaOtr(Xm1, Ym1,Um, Xg1, Yg1,Ug,XP,YP,P);

Проверка на принадлежность точки пересечения XP,YP отрезку линии чертежа:

if P=1 then PikOtr(XP,YP,Xm1,Ym1,Xm2,Ym2,P);

Проверка на принадлежность точки пересечения XP,YP отрезку линии выделенной области:

if P=1 then PikOtr(XP,YP,Xg1,Yg1,Xg2,Yg2,P);

if P=1 then begin

Ps:=Ps+1; {наличие точки пересечения}

Xs:=XP; Ys:=YP; {координаты точки пересечения}

DlinaL(Xm1,Ym1,Xs,Ys,L); {расстояние от начала отрезка

до точки пересечения}

if L>0 then

Запись в текущий файл e с сортировкой строк по возрастанию L:

StrokBox( e, Ps, L>, Xg1, Yg1, Xg2, Yg2, Xs, Ys );

end;

Until E=Nkg; {номер последней строки в файле}

if Ps=0 then begin

Проверка на принадлежность начальной точки отрезка Xm1,Ym1 выделенной области:

Tch_Obl(Xm1,Ym1,X1,Y1,X2,Y2,P);

if P=1 then

Отрезок расположен внутри области и его следует записать в файл o:

RisLineBox( o, 1, Nao, Xm1, Ym1, Xm2, Ym2, XCm, YCm );

end;

Если есть точки пересечения, то необходимо выделить те участки, которые расположены внутри области (Procedure FiltrOtr):

if Ps>0 then FiltrOtr;

end;

 

 

Выделение и запись участков отрезка прямой

 

Procedure FiltrOtr; {определяет принадлежность области отрезков

прямой, пересекающей границы области, прори-

совывает их и записывает в текущий файл}

var Xm1s, Ym1s. Xk, Yk :Float;

begin

Xm1s:=Xm1; Ym1s:=Ymx; {запомнить начало отрезка}

Определяем направление измерений дуги:

if обход=1 then Hod:=2 else Hod:=1;

Repeat

Читаем с 1-й строки файл е, в котором записаны точки пересечения:

SledStrok( e, Ps, L>, Xg1, Yg1, Xg2, Yg2, Xs, Ys ),

DlinaL(Xm1,Ym1,Xs,Ys,L); {длина отрезка от начальной точки

до точки пересечения}

if L>0 theh begin

Определяем точку начала измерений дуг и максимальную длину дуги:

Tch_NiK(XCg,YCg,Xg1,Yg1,Xg2,Yg2,Xs,Ys,XTn,YTn,LDk);

TekUgol(Xm1, Ym1, Xm2, Ym2,Ug);

Определяем точку, до которой измеряется длина дуги. Она принадлежит отрезку (Xm1,Ym1,Xs,Ys):

OtrDug(Xm1,Ym1,Um,Xs,Ys,Ri,XP1,YP1,XP2,YP2,P);

PikOtr(XP1,YP1,Xm1,Ym1,Xs,Ys,P);

if P=1 then begin

Xk:=XP1; Yk:=YP1;

end

else begin

Xk:=XP2; Yk:=YP2;

end;

Измеряем длину дуги:

DlinaD(Xs,Ys,XTn,YTn,Xk,Yk,Hod,LD);

if LD<LDk then {записать в файл o}

RisLineBox( o, 1, Nao, Xm1, Ym1, Xs, Ys, XCo, YCo );

end;

Xm1:=Xs; Ym1:=Ys;

Until E=Nke; {конечный номер строки в файле}

 

 

Определяем длину последнего отрезка:

DlinaL(Xm1,Ym1,Xm2,Ym2,L);

if L>0 then begin

Определяем принадлежность последнего отрезка области, для чего выясним принадлежность области конечной точки (Xm2, Ym2):

Tch_Obl(Xm2,Ym2,X1,Y1,X2,Y2,P);

if P=1 then {записать в файл o}

RisLineBox( o, 1, Nao, Xm1, Ym1, Xm2, Ym2, XCo, YCo );

end;

Возвращаем первоначальные значения X и Y начала отрезка:

Xm1:=Xm1s; Ym1:=Ym1s;

end;

 

Определение дуг, расположенных в области

 

Если дуга не имеет точек пересечения с линиями границы области, но одна ее точка находится внутри области, то дуга расположен внутри области. Такую дугу следует записать в файл.

Дуга NK пересекается с линиями границы области (рис. 109). В этом случае следует в любой последовательнос-ти определить точки S1, S2, S3, S4, S5

Рис. 109 и записать в файл с сортировкой строк по возрастанию LD, где LD - длина дуги от начальной точки N до точки пересечения S.

 

Procedure Box_Dug;{оператор записи дуги в текущий файл}

var P, Pt, Ps :byte;

begin

Ps:=0; {счетчик записей точек пересечения}

Repeat

Читаем файл линий границы выделенной области с 1-ой строки:

SledLine( g, 1, Nag, Xg1, Yg1, Xg2, Yg2, XCg, YCg ),

TekUgol(Xg1, Yg1, Xg2, Yg2,Ug);

Определяем точку пересечения дуги (XCm,YCm,Xm1,Ym1,Xm2,Ym2) с линией области:

 

 

OtrDug(Xg1,Yg1,Ug,XCm,YCm,R,XP1,YP1,XP2,YP2,Pt);

Проверка на принадлежность точки пересечения (XP1,YP1) отрезку линии выделенной области:

if Pt=1 then PikOtr(XP1,YP1,Xg1,Yg1,Xg2,Yg2,P);

Проверка на принадлежность точки пересечения (XP1,YP1) дуге:

if P=1 then

. PikDug(XP1,YP1,XCm,YCm,Xm1,Ym1,Xm2,Ym2,Nam,P);

if P=1 then begin

Ps:=Ps+1; {наличие точки пересечения}

Xs:=XP1; Ys:=YP1; {координаты точки пересечения}

Определяем длину дуги чертежа от начала до точки пересечения S:

DlinaD(XСm,YСm,Xm1,Ym1,Xs,Ys,nam,LD);

if LD>0 then

Запись в текущий файл с сортировкой строк по возрастанию LD:

StrokBox( e, Ps, LD>, Xg1, Yg1, Xg2, Yg2, Xs, Ys );

end;

Проверка на принадлежность 2-ой точки пересечения (XP2,YP2) отрезку линии выделенной области:

if Pt=1 then PikOtr(XP2,YP2,Xg1,Yg1,Xg2,Yg2,P);

Проверка на принадлежность точки пересечения (XP2,YP2) дуге:

if P=1 then

. PikDug(XP2,YP2,XCm,YCm,Xm1,Ym1,Xm2,Ym2,Nam,P);

if P=1 then begin

Ps:=Ps+1; {наличие точки пересечения}

Xs:=XP2; Ys:=YP2; {координаты точки пересечения}

Определяем длину дуги чертежа от начала до точки пересечения S:

DlinaD(XCm,YCm,Xm1,Ym1,Xs,Ys,nam,LD);

if LD>0 then

Запись в текущий файл с сортировкой строк по возрастанию LD:

StrokBox( e, Ps, LD>, Xg1, Yg1, Xg2, Yg2, Xs, Ys );

end;

Until E=Nkg; {номер последней строки в файле}

if Ps=0 then begin

Проверка на принадлежность начальной точки дуги (Xm1,Ym1) выделенной области

Tch_Obl(Xm1,Ym1,X1,Y1,X2,Y2,P);

if P=1 then

{дуга расположена внутри области}

 

 

RisLineBox( o, 2, Nam, Xm1, Ym1, Xm2, Ym2, XCm, YCm );

end;

Если есть точки пересечения, то необходимо выделить те участки

дуги, которые расположены внутри области (Procedure FiltrDug):

if Ps>0 then FiltrDug;

end;

 

Выделение и запись участков дуги

 

Procedure FiltrDug; {определение принадлежности дуг области,

прорисовка их и запись в текущий файл}

var Xm1s, Ym1s :Float;

begin

Xm1s:=Xm1; Ym1s:=Ym1;

Определяем направление измерений дуги:

if обход=1 then Hod:=2 else Hod:=1;

Repeat

Читаем с 1-й строки файл е, в котором записаны точки пересечения:

SledStrok(e, Ps, LD>, Xg1, Yg1, Xg2, Yg2,Xs, Ys);

Длина дуги от начальной точки до точки пересечения:

DlinaD(XCm,YCm,Xm1,Ym1,Xs,Ys,Nam,LD1);

if LD1>0 then begin

Определяем точку (XTn,YTn) начала измерений дуг и максимальную длину дуги LDk:

Tch_NiK(XCg,YCg,Xg1,Yg1,Ug,Xs,Ys,XTn,YTn,LDk);

Определяем конечную точку для измерения длины дуги:

DugDug(XCm,YCm,R,Xs,Ys,Ri,XP1,YP1,XP2,YP2,P);

{Ri - радиус дуги измерений}

Измеряем длины дуг до точек пересечения:

DlinaD(Xs,Ys,XTn,YTn,XP1,YP1,Hod,LD1);

DlinaD(Xs,Ys,XTn,YTn,XP2,YP2,Hod,LD2);

Конечной точке соответствует меньшая длина дуги:

if LD1<LD2 then LD:=LD1 else LD:=LD2;

if LD<LDk then {записать в файл o}

RisLineBox(о, 2, Nam, Xm1, Ym1, Xs, Ys, XCm, YCm );

end;

Xm1:=Xs; Ym1:=Ys;

Until E=Nke;

Проверка на принадлежность области конечной точки дуги:

 

Tch_Obl(Xm2,Ym2,X1,Y1,X2,Y2,P);

if P=1 theh

{отрезок расположен внутри области}

RisLineBox(о, 2, Nam, Xs, Ys, Xm2, Ym2, XCm, YCm );

Возвращаем первоначальные значения X и Y начала отрезка:

Xm1:=Xm1s; Ym1:=Ym1s;

end;

 

Программа записи линий чертежа в файл области

 

Procedure Box_Lin;

{строка исполняемого графического файла}

var m, Em, Nam :byte; Xm1, Ym1, Xm2, Ym2, XCm, YCm :float;

{строка линий границы области}

var g, Eg, Nag :byte; Xg1, Yg1, Xg2, Yg2, XCg, YCg :float;

{строка линий внутри области}

var o, Eo, Nao :byte; Xo1, Yo1, Xo2, Yo2, XCo, YCo :float;

{строка сортировки по параметру L}

var e, N :byte; L>, Xe1, Ye1, Xe2, Ye2, XCe, YCe :float;

{границы области по X и Y}

var X1, Y1, X2, Y2 :float;

{прочие переменные}

var X, Y, U, Um, Ug, Uo, Us, Xs, Ys :float:

P, Pn, Pk, Ps, E, обход. ход :byte;

Nkm, Nko, Nke; Nkg :integer;

 

begin

Repeat

Начиная с 1-й строки, последовательно читаем файл линий чертежа и заполняем строку параметров.

SledLine( m, Em, Napr, Xm1, Ym1, Xm2, Ym2, XCm, YCm );

if Em=1 then Box_Otr; {тип линии - отрезок прямой}

if Em=2 then Box_Dug; {тип линии - дуга}

Until E=Nkm;

end;

 

Задача 2. Записать в файл границы заштрихованного контура (рис. 110).

Диалог пользователя:

 

‘Укажите курсором линию контура’ X,Y.

 

Заштрихованный контур в нашем случае ограничен 2-я линиями:

- наружная состоит из отрезков прямых, дуг и окружности;

- внутренняя содержит отрезки прямых и дуги.

Следовательно, следует указать в любой последовательности обе линии, например, курсором внутри области поставить точку О. Программное обеспечение в этом случае находит ближайший элемент линии наружного контура и на нем ближайшую от О точку А или В, которая принимается за начальную точку обхода по контуру в направлении конечной точки элемента. Возврат в эту точку означает окончание выбора линии контура. Выбранный контур для наглядности и контроля со стороны пользователя желательно прорисовать другим цветом, а его линии записать во временный файл для продолжения работы с контуром.

 
 

Рис. 110

Procedure Lin_Kontur;

Строка параметров линий, образующих контур:

var Em, Nam : byte: Xm1, Ym1, Xm2, Ym2, XCm, YCm :float:

Строка параметров линий контура:

var Eo, Nao : byte: Xo1, Yo1, Xo2, Yo2, XCo, YCo :float:

Строка параметров очередного отрезка

var Et, Nat : byte; Xt1, Yt1, Xt2, Yt2, XCt, YCt :float;

Прочие переменные:

var Xs, Ys, L, L1, Lmin, Li :float;

P, P1, P2, обход, ход :byte;

begin

Nach_Lin; {выбор начала и направления обхода}

Och_Line; {выбор и запись в текущий файл очередной линии}

end;

Выбор начала и направления обхода

Procedure Nach_Lin; {выбор начальной линии}

var XA,YA,XB,YB :float;

Pd :byte;

begin

L:=0; Pd:=0;

Repeat

Читать с 1-й строки файл линий и заполнить строку параметров:

SledLine(Bx, El, Nag, Xm1, Ym1, Xm2, Ym2, XCm, YCm );

if Em=2 then begin { дуга }

Соединить указанную курсором точку (ХO, YO) с центром дуги (ХЦ, YЦ) и определить текущий угол этой прямой:

TekUgol(XO,YO,XCm,YCm,U);

Радиус дуги:

DlinaL(XCm,YCm,Xm1,Ym1,R);

Точки пересечения прямой ОЦ с дугой:

OtrDug(XO,YO,U,XCm,YCm,R,XP1,YP1,XP2,YP2,P);

Принадлежность точки (XP1,YP1) дуге:

PikDug(XP1,YP1,Xm1,Ym1,Xm2,Ym2,Nam,P1);

Принадлежность точки (XP1,YP1) отрезку:

PikOtr(XP1,YP1,XО,YО,XЦ,YЦ,P2);

if P1=1 and P2=1 then begin

XA:=XP1; YA:=YP1;

end

else begin

XA:=XP2; YA:=YP2;

end;

Точка начала обхода:

Xs:=XA; Ys:=YA;

Расстояние от точки О до дуги:

DlinaL(XО,YО,XА,YА,L1);

end;

if Em=1 then begin {отрезок прямой}

TekUgol(Xm1,Ym1,Xm2,Ym2,U);

Перпендикуляр на прямую из О:

DwaOtr(Xm1, Ym1,U, XO, YO,U+90,XP,YP,P);

XB:=XP; YB:=YP;

 

 

Точка начала обхода:

Xs:=XB; Ys:=YB;

Расстояние от точки О до прямой:

DlinaL(XО,YО,XB,YB,L1);

end;

Pd:=Pd+1; {Номер цикла}

1- й цикл:

if Pd=1 then begin

Расстояние от точки О до элемента:

L:= L1;

Параметры начального отрезка обхода контура:

Eo:=Em; XCo:=XCm; YCo:=YCm;

Xo1:=Xs; Yo1:=Ys; Xo2:=Xm2; Yo2:=Ym2;

end;

Очередной цикл:

if Pd >1 and L>L1 then begin

Заменить параметры начального элемента обхода контура

L:= L1;

Eo:=Em; XCo:=XCm; YCo:=YCm;

Xo1:=Xs; Yo1:=Ys; Xo2:=Xm2; Yo2:=Ym2;

end;

Until E=Nkm;

Направление обхода контура определяется операторами Sopr_LL (центр и направление дуги сопряжения прямых) и Sopr_LD (центр и направление дуги сопряжения прямой и дуги). Направление в них непосредственно определяет рассмотренный выше оператор:

Naprawl(XC,YC,Xn,Yn,Xk,Yk,обход) }

if Eo=1 then Sopr_LL(XC, YC, обход)

else Sopr_LD(XC, YC, обход);

Чтобы замкнуть контур в точке S(Xs,Ys), в файл следует добавить отрезок линии от начальной точки до точки пересечения S. По окончании выбора линии контура его следует удалить.

RisLineBox( Bx, Em, Nam, Xm1, Ym1, Xs, Ys, XCm, YCm );

end;

Алгоритм выбора линий контура

Рассмотрим алгоритм выбора линий контура от начальной точки Na прямой a(Na,Ka) в направлении ‘обход’ (рис. 111). Ее параметры

 

 

записаны предыдущим оператором Nach_Lin в строку линий контура (Xo1:=Xs; Yo1:=Ys; Xo2:=Xm2; Yo2:=Ym2).

Далее определяются точки пересечения S1, S2 этого элемента с другими, содержащимися в файле и сортируются по наименьшему расстоянию до начала исходного элемента(точка Na). Одновременно определяется длина дуги DL.

 
 

Если через точку S2 проходят 2 и более элементов (в данном случае дуга d и прямая с), то выбирается элемент с меньшим углом LD. В данном случае часть дуги d с начальной точкой S2 и конечной точкой Kd. Отрезок прямой a от начальной точки Na до точки S2 записывается в файл, содержащий линии определяемого контура.

Рис. 111

 

Дуга d становится начальным элементом. Предыдущий цикл повторяется. В этом цикле в файл будет записана дуга с начальной точкой S2 и конечной - S3.

Начальным элементом в следующем цикле будет отрезок S3Kc, на котором нет точки пересечения. В этом случае он будет записан в файл, а начальным элементом в следующем цикле будет тот же отрезок, но с обратным направлением KcS2.

Выбор контура будет закончен, если координаты конечной точки

 

 

очередного элемента будут равны Xs, Ys.

 

Выбор очередной линии

Procedure Och_Line; {выбор и запись линий контура}

var Xs1; Ys1, Lmin, Li :Float; Pd :byte;

begin

Pd:=0;

Repeat

SledLine( Bx, Em, Nam, Xm1, Ym1, Xm2, Ym2, XCm, YCm );

if Em=1 then TekUgol(Xm1, Ym1, Xm2, Ym2,Um);

if Em=2 then DlinaL(Xm1, Ym1, XCm , YCm ,R);

if Eo=1 and Em=1 then O_O;

if Eo=1 and Em=2 then O_D;

if Eo=2 and Em=1 then D_O;

if Eo=2 and Em=2 then D_D;

Записать начальный отрезок в файл линий границы контура:

RisLineBox( o, Eo, Nao, Xo1, Yo1, Xo2, Yo2, XCo, YCo );

Заменить строку параметров начального элемента параметрами бывшего очередным:

Eo:=Et; Nao:=Nat;

Xo1:=Xt1; Yo1:=Yt1; Xo2:=Xt2; Yo2:=Yt2; XCo:=XCt; YCo:=YCt;

Until Xt2=Xs and Yt2=Ys;

Записать в файл конечную линию обхода контура:

RisLineBox( o, Et, Nat, Xt1, Yt1, Xt2, Yt2, XCt, YCt );

end;

 

Начальный элемент - отрезок, очередной - отрезок

Procedure O_O;

Оператор определяет точку пресечения Р начального элемента - отрезка o(o1,o2) с текущим элементом - отрезком m(m1,m2). Если

Li < Lmin,то отрезок m делится на 2 отрезка Рm1 и Pm2 (рис. 112).

Далее оператор определяет, который из них может быть очередной линией контура после отрезка о.

begin

Определена Lmin при условии, что не было пересечений с текущим элементом (отрезком прямой или дугой):

 

 
 

Рис. 112

 

if Pd=0 then DlinaL(Xo1,Yo1,Xo2,Yo2,Lmin); {Pd - номер точки P на начальном элементе. Если не было пересечения с текущим элементом, Рd =0}

TekUgol(Xo1,Yo1,Xo2,Yo2,Uo); {начальной прямой}

TekUgol(Xm1,Ym1,Xm2,Ym2,Um); {текущей прямой}

Точка пересечения элементов:

DwaOtr(Xm1, Ym1,Um, Xo1, Yo1,Uo,XP,YP,P);

Принадлежность точки пересечения текущему элементу:

if P=1 then PikOtr(XP,YP,Xm1,Ym1,Xm2,Ym2,P);

Принадлежность точки пересечения начальному элементу:

if P=1 then PikOtr(XP,YP,Xo1,Yo1,Xo2,Yo2,P);

{Если P=1, то отрезки пересекаются}

if P=1 then begin

Расстояние точки пересечения от начала начального элемента:

DlinaL(Xo1,Yo1,XP,YP,Li);

if Li > 0 and Li <= Lmin then begin

if Pd=0 then

Определена начальная точка измерения дуги и LDk:

Tch_NiK(XCo,YCo,Xo1,Yo1,Xo2,Yo2,XP,YP,XTn,YTn,LDk);

Длина текущего отрезка от точки пересечения до конца:

DlinaL(XP,YP,Xm2,Ym2,L);

if L>0 then begin

Определена точка Tk(XTk,YTk) на отрезке(XP,YP.Xm2,Ym2):

OtrDug(XP,YP,Um,XP,YP,Ri,XP1,YP1,XP2,YP2,P);

PikOtr(XP1,YP1,XP,YP,Xm2,Ym2,P);

 

 

if P=1 then begin

XTk:=XP1; YTk:=YP1;

end

else begin

XTk:=XP2; YTk:=YP2;

end;

Определена длина дуги от Tn до Tk:

DlinaD(XP,YP,XTn,YTn,XTk,YTk,Hod,LD);

if LD<LDk then begin

Записать в текущую строку отрезок, который может быть очередным:

Et:=1; Xt1:=XP; Yt1:=YP; Xt2:=Xm2; Yt2:=Ym2;

Записать номер пересечения, новое значение LDk и Lmin:

Pd:=Pd+1; LDk:=LD; if Li<Lmin then Lmin:=Li;

end;

end;

То же выполнено для оставшейся части текущего отрезка:

DlinaL(XP,YP,Xm1,Ym1,L);

if L>0 then begin

Определен Um, т.к. изменилось направление:

TekUgol(XP,YP,Xm1,Ym1,Um);

OtrDug(XP,YP,Um,XP,YP,Ri,XP1,YP1,XP2,YP2,P);

PikOtr(XP1,YP1,XP,YP,Xm1,Ym1,P);

if P=1 then begin

XTk:=XP1; YTk:=YP1;

end

else begin

XTk:=XP2; YTk:=YP2;

end;

DlinaD(XP,YP,XTn,YTn,XTk,YTk,Hod,LD);

if LD<LDk then begin

Записать в текущую строку отрезок, который может быть очередным:

Et:=1; Xt1:=XP; Yt1:=YP; Xt2:=Xm2; Yt2:=Ym2;

Записать номер пересечения, новое значение LDk и Lmin:

Pd:=Pd+1; LDk:=LD; if Li<Lmin then Lmin:=Li;

end;

end;

 

 

if Li<Lmin then

{Изменилась длина начального отрезка}

Xo2:=XP; Yo2:=YP;

end;

end;

end;

Начальный элемент - отрезок, очередной - дуга

 

Procedure O_D;

Оператор определяет точку пресечения Р начального элемента - отрезка o(o1,o2) с текущим элементом - дугой m(m1,m2).

 
 

Если Li < Lmin,то дуга m делится на 2 части Рm1 и Pm2 (рис. 113). Далее оператор определяет, которая из дуг может быть очередной линией контура после отрезка о.

 

Рис. 113

begin

Определена Lmin при условии, что не было пересечений с текущим

элементом (отрезком прямой или дугой):

if Pd=0 then DlinaL(Xo1,Yo1,Xo2,Yo2,Lmin); {Pd - номер точки P на начальном элементе. Если не было пересечения с текущим элементом, то Рd =0}

TekUgol(Xo1,Yo1,Xo2,Yo2,Uo); {начальной прямой}

DlinaL(XСm,YCm,Xm1,Ym1,R); {радиус текущей дуги}

Определены 2 точки пересечении прямой с дугой:

OtrDug(Xo1,Yo1,Uo,XCm,YCm,R,XP1,YP1,XP2,YP2,P);

Принадлежность Р1 начальному элементу:

 

if P=1 then PikOtr(XP1,YP1,Xo1,Yo1,Xo2,Yo2,P1);

Принадлежность Р1 текущему элементу:

if P1=1 then

PikDug(XP1,YP1,XCm,YCm,Xm1,Ym1,Xm2,Ym2,Nam,P2);

if P1=1 and P2=1 then P3=1 else P3=0;

Принадлежность Р2 начальному элементу:

PikOtr(XP2,YP2,Xo1,Yo1,Xo2,Yo2,P1);

Принадлежность Р2 текущему элементу:

if P1=1 then

PikDug(XP2,YP2,XCm,YCm,Xm1,Ym1,Xm2,Ym2,Nam,P2);

if P1=1 and P2=1 then P4=1 else P4=0;

{Если P3=1 или P4=1, то элементы пересекаются. Если Р3=1 и Р4=1, то выбрать точку пересечения, которая ближе к началу начального элемента}

if P3=1 and P4=1 then begin

DlinaL(Xo1,Yo1,XP1,YP1,L1);

DlinaL(Xo1,Yo1,XP2,YP2,L2);

if L1<L2 then begin

XP:=XP1; YP:=YP1; Li:=L1;

end

else begin

XP:=XP2; YP:=YP2; Li:=L2;

end;

end;

if P3=1 and P4=0 then begin

XP:=XP1; YP:=YP1; Li:=L1;

end;

if P3=0 and P4=1 then begin

XP:=XP2; YP:=YP2; Li:=L2;

end;

if Li > 0 and Li <= Lmin then begin

if Pd=0 then

Определена начальная точка(XTn,YTn) измерения дуги и LDk:

Tch_NiK(XCo,YCo,Xo1,Yo1,Xo2,Yo2,XP,YP,XTn,YTn,LDk);

Измерить длину части текущей дуги от Р до конца:

DlinaD(XCm,YCm,XP,YP,Xm2,Ym2,Nam,LD);

if LD>0 then begin

Определена конечная точка(XTk,YTk) для измерения длины дуги:

 

 

DugDug(XCm,YCm,R,XP,YP,Ri,XP1,YP1,XP2,YP2,P);

PikDug(XP1,YP1,XCm,YCm,XP,YP,Xm2,Ym2,Nam,P);

if P=1 then begin

XTk:=XP1; YTk:=YP1;

end

else begin

XTk:=XP2; YTk:=YP2;

end;

Определена длина дуги:

DlinaD(XP,YP,XTn,YTn,XTk,YTk,Hod,LD);

if LD<LDk then begin

Записать в текущую строку элемент, который может быть очередным:

Et:=2; Xt1:=XP; Yt1:=YP; Xt2:=Xm2; Yt2:=Ym2;

XCt:=XCm; YCt:=YCm;

Записать номер пересечения, новое значение LDk и Lmin:

Pd:=Pd+1; LDk:=LD;

if Li<Lmin then begin

Lmin:=Li;

Изменилась длина начального отрезка:

Xo2:=XP; Yo2:=YP;

end;

end;

end;

Для второй части дуги необходимо изменить направление на противоположное:

if Nam=1 then Nam:=2 else Nam:=1;

DlinaD(XCm,YCm,XP,YP,Xm1,Ym1,Nam,LD);

if LD>0 then begin

DugDug(XCm,YCm,R,XP,YP,Ri,XP1,YP1,XP2,YP2,P);

PikDug(XP1,YP1,XCm,YCm,XP,YP,Xm1,Ym1,Nam,P);

if P=1 then begin

XTk:=XP1; YTk:=YP1;

end

else begin

XTk:=XP2; YTk:=YP2;

end;

DlinaD(XP,YP,XTn,YTn,XTk,YTk,Hod,LD);

 

 

if LD<LDk then begin

Et:=2; Xt1:=XP; Yt1:=YP; Xt2:=Xm1; Yt2:=Ym1;

XCt:=XCm; YCt:=YCm;

Записать номер пересечения, новое значение LDk и Lmin:

Pd:=Pd+1; LDk:=LD;

if Li<Lmin then begin

Lmin:=Li;

Изменилась длина начального отрезка:

Xo2:=XP; Yo2:=YP;

end;

end;

end;

end;

end;

 

Начальный элемент - дуга, очередной - отрезок

 

Procedure D_O;

Оператор определяет точку пресечения Р начального элемента - дуги o(o1,o2) с текущим элементом - отрезком m(m1,m2).

Если Li < Lmin,то отрезок m делится на 2 части Рm1 и Pm2 (рис. 114). Далее оператор определяет, который из отрезков может быть очередной линией контура после дуги о.

 
 

Рис. 114

begin

Определена Lmin при условии, что не было пересечений с текущим

элементом (отрезком прямой или дугой):

 

if Pd=0 then DlinaD(XCo,YCo,Xo1,Yo1,Xo2,Yo2,Nao,Lmin);

{Pd - номер точки P на начальном элементе. Если не было

пересечения с текущим элементом, то Рd =0}

TekUgol(Xm1,Ym1,Xm2,Ym2,Um); {текущей прямой}

DlinaL(XСo,YCo,Xo1,Yo1,R); {радиус начальной дуги}

Определены точки пересечения прямой с дугой:

OtrDug(Xm1,Ym1,Um,XCo,YCo,R,XP1,YP1,XP2,YP2,P);

Принадлежность Р1 текущему элементу:

if P=1 then PikOtr(XP1,YP1,Xm1,Ym1,Xm2,Ym2,P1);

Принадлежность Р1 начальному элементу:

if P1=1 then

PikDug(XP1,YP1,XCo,YCo, Xo1,Yo1,Xo2,Yo2,Nao,P2);

if P1=1 and P2=1 then P3=1 else P3=0;

Принадлежность Р2 текущему элементу:

if P=1 then PikOtr(XP2,YP2,Xm1,Ym1,Xm2,Ym2,P1);

Принадлежность Р2 начальному элементу:

if P1=1 then

PikDug(XP2,YP2,XCo,YCo,Xo1,Yo1,Xo2,Yo2,Nao,P2);

if P1=1 and P2=1 then P4=1 else P4=0;

Если Р3=1 и Р4=1, то выбрать точку пересечения, которая ближе к началу начального элемента:

if P3=1 and P4=1 then begin

DlinaD(XCo,YCo,Xo1,Yo1,XP1,YP1,Nao,L1);

DlinaD(XCo,YCo,Xo1,Yo1,XP2,YP2,Nao,L2);

if L1<L2 then begin

XP:=XP1; YP:=YP1; Li:=L1;

end

else begin

XP:=XP2; YP:=YP2; Li:=L2;

end;

end;

if P3=1 and P4=0 then begin

XP:=XP1; YP:=YP1; Li:=L1;

end;

if P3=0 and P4=1 then begin

XP:=XP2; YP:=YP2; Li:=L2;

end;

if Li > 0 and Li <= Lmin then begin

 

 

if Pd=0 then

Определена точка измерения дуги (XTn,YTn) и LDk:

Tch_NiK(XCo,YCo,Xo1,Yo1,Xo2,Yo2,XP,YP,XTn,YTn,LDk);

Длина текущего отрезка от точки пересечения до конца:

DlinaL(XP,YP,Xm2,Ym2,L);

if L>0 then begin

Определена точка Tk(XTk,YTk) на отрезке(XP,YP.Xm2,Ym2):

OtrDug(XP,YP,Um,XP,YP,Ri,XP1,YP1,XP2,YP2,P);

PikOtr(XP1,YP1,XP,YP,Xm2,Ym2,P);

if P=1 then begin

XTk:=XP1; YTk:=YP1;

end

else begin

XTk:=XP2; YTk:=YP2;

end;

Определена длина дуги от Tn до Tk:

DlinaD(XP,YP,XTn,YTn,XTk,YTk,Hod,LD);

if LD<LDk then begin

Записать в текущую строку отрезок, который может быть очередным:

Et:=1; Xt1:=XP; Yt1:=YP; Xt2:=Xm2; Yt2:=Ym2;

Записать номер пересечения, новое значение LDk и Lmin:

Pd:=Pd+1; LDk:=LD; if Li<Lmin then Lmin:=Li;

end;

end;

То же выполнено для оставшейся части текущего отрезка:

DlinaL(XP,YP,Xm1,Ym1,L);

if L>0 then begin

Определен Um, т.к. изменилось направление:

TekUgol(XP,YP,Xm1,Ym1,Um);

OtrDug(XP,YP,Um,XP,YP,Ri,XP1,YP1,XP2,YP2,P);

PikOtr(XP1,YP1,XP,YP,Xm1,Ym1,P);

if P=1 then begin

XTk:=XP1; YTk:=YP1;

end

else begin

XTk:=XP2; YTk:=YP2;

end;

 

 

 

DlinaD(XP,YP,XTn,YTn,XTk,YTk,Hod,LD);

if LD<LDk then begin

Записать в текущую строку отрезок, который может быть очередным:

Et:=1; Xt1:=XP; Yt1:=YP; Xt2:=Xm2; Yt2:=Ym2;

Записать номер пересечения, новое значение LDk и Lmin:

Pd:=Pd+1; LDk:=LD; if Li<Lmin then Lmin:=Li;

end;

end;

if Li<Lmin then

{Изменилась длина начального отрезка}

Xo2:=XP; Yo2:=YP;

end;

end;

end;

 

Procedure D_D;

Оператор определяет точку пресечения Р начального элемента - дуги o(o1,o2) с текущим элементом - дугой m(m1,m2).

Если Li < Lmin,то дуга m делится на 2 части Рm1 и Pm2 (рис. 115). Далее оператор определяет, которая из дуг может быть очередной линией контура после дуги о.

 

 
 

Рис. 115

begin

Определена Lmin при условии, что не было пересечений с текущим

элементом (отрезком прямой или дугой):

 

 

if Pd=0 then DlinaD(XCo,YCo,Xo1,Yo1,Xo2,Yo2,Nao,Lmin);

{Pd - номер точки P на начальном элементе. Если не было пересечения с текущим элементом, то Рd =0}

DlinaL(XСm,YCm,Xm1,Ym1,Rm); {радиус текущей дуги}

DlinaL(XСo,YCo,Xo1,Yo1,R); {радиус начальной дуги}

Определены точки пересечения дуг:

DugDug(XCm,YCm,Rm,XCo,YCo,R,XP1,YP1,XP2,YP2,P);

Принадлежность Р1 текущему элементу:

if P=1 then

PikDug(XP1,YP1,XCm,YCm,Xm1,Ym1,Xm2,Ym2,Nam,P1);

Принадлежность Р1 начальному элементу:

if P1=1 then

PikDug(XP1,YP1,XCo,YCo,Xo1,Yo1,Xo2,Yo2,Nao,P2);

if P1=1 and P2=1 then P3=1 else P3=0;

Принадлежность Р2 текущему элементу:

if P=1 then

PikOtr(XP2,YP2,XCm,YCm,Xm1,Ym1,Xm2,Ym2,P1);

Принадлежность Р2 начальному элементу:

if P1=1 then

PikDug(XP2,YP2,XCo,YCo,Xo1,Yo1,Xo2,Yo2,Nao,P2);

if P1=1 and P2=1 then P4=1 else P4=0;

Если Р3=1 и Р4=1, то выбрать точку пересечения, которая ближе к началу начального элемента:

if P3=1 and P4=1 then begin

DlinaD(XCo,YCo,Xo1,Yo1,XP1,YP1,Nao,L1);

DlinaD(XCo,YCo,Xo1,Yo1,XP2,YP2,Nao,L2);

if L1<L2 then begin

XP:=XP1; YP:=YP1; Li:=L1;

end

else begin

XP:=XP2; YP:=YP2; Li:=L2;

end;

end;

if P3=1 and P4=0 then begin

XP:=XP1; YP:=YP1; Li:=L1;

end;

if P3=0 and P4=1 then begin

XP:=XP2; YP:=YP2; Li:=L2;

end;

 

if Li > 0 and Li <= Lmin then begin

if Pd=0 then

Определена точка измерения дуги (XTn,YTn) и LDk:

Tch_NiK(XCo,YCo,Xo1,Yo1,Xo2,Yo2,XP,YP,XTn,YTn,LDk);

Измерена длина части текущей дуги от Р до конца:

DlinaD(XCm,YCm,XP,YP,Xm2,Ym2,Nam,LD);

if LD>0 then begin

Определена конечная точка(XTk,YTk) для измерения длины дуги:

DugDug(XCm,YCm,R,XP,YP,Ri,XP1,YP1,XP2,YP2,P);

PikDug(XP1,YP1,XCm,YCm,XP,YP,Xm2,Ym2,Nam,P);

if P=1 then begin

XTk:=XP1; YTk:=YP1;

end

else begin

XTk:=XP2; YTk:=YP2;

end;

Определена длина дуги:

DlinaD(XP,YP,XTn,YTn,XTk,YTk,Hod,LD);

if LD<LDk then begin

Записать в текущую строку элемент, который может быть очередным:

Et:=2; Xt1:=XP; Yt1:=YP;

Xt2:=Xm2; Yt2:=Ym2;

XCt:=XCm; YCt:=YCm;

Записать номер пересечения, новое значение LDk и Lmin:

Pd:=Pd+1; LDk:=LD;

if Li<Lmin then begin

Lmin:=Li;

Изменилась длина начального отрезка:

Xo2:=XP; Yo2:=YP;

end;

end;

end;

Для второй части дуги необходимо изменить направление на противоположное:

if Nam=1 then Nam:=2 else Nam:=1;

DlinaD(XCm,YCm,XP,YP,Xm1,Ym1,Nam,LD);

if LD>0 then begin

DugDug(XCm,YCm,R,XP,YP,Ri,XP1,YP1,XP2,YP2,P);

 

 

PikDug(XP1,YP1,XCm,YCm,XP,YP,Xm1,Ym1,Nam,P);

if P=1 then begin

XTk:=XP1; YTk:=YP1;

end

else begin

XTk:=XP2; YTk:=YP2;

end;

DlinaD(XP,YP,XTn,YTn,XTk,YTk,Hod,LD);

if LD<LDk then begin

Et:=2; Xt1:=XP; Yt1:=YP; Xt2:=Xm1; Yt2:=Ym1;

XCt:=XCm; YCt:=YCm;

Записать номер пересечения, новое значение LDk и Lmin:

Pd:=Pd+1; LDk:=LD;

if Li<Lmin then begin

Lmin:=Li;

Изменилась длина начального отрезка:

Xo2:=XP; Yo2:=YP;

end;

end;

end;

end;

end;

Задача 3. Определить взаимное положение прямой и поверхности конуса (рис. 116).

Поверхность типа конуса будет задана:

- периметром основания, записанным в файл, где каждая строка-

линия;

- текущей базой периметра БТ(X,Y,Z), например центром окружности;

- углами наклона плоскости основания a и b;

- вершиной конуса S(X,Y,Z).

Такое параметрическое описание поверхности позволяет выполнять пересчет координат методами начертательной геометрии при любом изменении положения объекта в пространстве.

Текущие параметры поверхности выводятся в строку параметров и могут использоваться программным обеспечением.

При наличии параметрического описания поверхностей и линий диалог пользователя при работе с объектами будет сводиться:

Указать курсором попарно элементы или поверхности и оператор

выполняемого с ними действия’.

 

 
 

Рис. 116

 

Procedure El_Pw(El,Pw :tekst; var X[N],Y[N],Z[N] :float; P:byte);

 

begin

Принадлежность точки S прямой AB:

PikOtr(XS2, ZS2, XA2, ZA2, XB2, ZB2, P1);

PikOtr(XS1, YS1, XA1, YA1, XB1, YB1, P2);

if P1=1 and P2=1 then begin

P:=1; {прямая проходит через вершину}

K = S - точка пересечения прямой с поверхностью конуса

XK:= XS; YK:= YS; ZK:= S;

Вторую общую точку с поверхностью прямая может иметь при пересечении с плоскостью основания, если точка пересечения расположена внутри периметра.

else begin

Определяем взаимное положение плоскостей S(S, AB) и D(r),

где r - периметр основания.

 

Линия пересечения плоскостей определена 2-мя точками(N(X,Y,Z) и M(X,Y,Z)), которые являются точками пересечения 2-х прямых плоскости S(S, AB) с плоскостью D(r). Одной из таких прямых может быть исходная прямая АВ, если угол наклона ее к D(r) j <> 0.

Другие прямые проходят через вершину S и пересекают АВ.

TekUgol(XA2,ZA2,XB2,ZB2,UAB2);

TekUgol(XA1,ZA1,XB1,YB1,UAB1);

TekUgol(XO2,ZO2,XT2,ZT2,UOT2);

DwaOtr(XA2,ZA2,UAB2,XS2,ZS2,130,XF2,ZF2,P5);

DwaOtr(XA1,YA1,UAB1,XF2,ZF2, 90,XF1,YF1,P5);

{ SF - прямая в плоскости S(S, AB) }

TekUgol(XS1,YS1,XF1,YF1,USF1);

DwaOtr(XS2,ZS2,130, XO2,ZO2,UOT2 ,XN2,ZN2,P5);

DwaOtr(XS1,YS1, USF1, XN2,ZN2,90 ,XN1,YN1,P5);

{N(N1,N2) - точка пересечения прямой SF с плоскостью

основания конуса}

DwaOtr(XA2,ZA2,UAB2, XO2,ZO2,UOT2 ,XM2,ZM2,P3);

if P3=1 then begin

DwaOtr(XA1,YA1,UAB1,XM2,ZM2,90,XM1,YM1,P5);

{М(M1,M2) - точка пересечения прямой AB с плоскостью

основания конуса}

PikOtr(XM2, ZM2, XR2, ZR2,XT2, ZT2, P4);

if P4=1 then

OtrDug(XA1,YA1,UAB1,XO1,YO1,R,XH1,YH1,XL2,YL2,P4);

if P4=1 then PikOtr(XM1, YM1, XH1, YH1,XL1, YL1, P4);

{Если P4=1, то точка М находится внутри периметра

основания конуса. Или оператор:

Tch_Obl(X,Y,X1,Y1,X2,Y2,P)}

end

else begin

{если AB не пересекает плоскость основания}

DwaOtr(XA2,ZA2,UAB2,XS2,ZS2,60,XG2,ZG2,P5);

DwaOtr(XA1,YA1,UAB1,XG2,ZG2, 90,XG1,YG1,P5);

{ SG - прямая в плоскости S(S, AB) }

TekUgol(XS1,YS1,XG1,YG1,USG1);

DwaOtr(XS2,ZS2,60, XO2,ZO2,UOT2 ,XM2,ZM2,P5);

DwaOtr(XS1,YS1, USG1, XM2,ZM2,90 ,XM1,YM1,P5);

 

 

{М(M1,M2) - точка пересечения прямой SG с плоскостью

основания конуса}

end;

if P1=1 and P2=1 and P4=1 then begin

P:=1; {есть пересечение}

XK:=XM2; YK:=YM1; ZK:=ZM2;

{прямая проходит через вершину и пересекается с

основанием в точке К=М}

end

else begin

TekUgol(XM1,YM1,XN1,YN1,UMN1);

OtrDug(XM1,YM1,UMN1,XS1,YS1,R,XC1,YC1,XE2,YE2,P5);

if P5=0 then P:=0 {прямая проходит мимо}

else begin

TekUgol(XS1,YS1,XC1,YC1,USC1);

DwaOtr(XS1,YS1, USC1, XA1,YA1,UAB1 ,XK1,YK1,P5);

DwaOtr(XA2,ZA2,UAB2, XK1,YK1,90 ,XK2,ZK2,P5);

if (XC1-XE1<0.05 and (YC2-YE2)<0.05 then begin

P:=1; {прямая касается в точке K(XK1,YK1,ZK2}

end

else begin

TekUgol(XS1,YS1,XE1,YE1,USE1);

DwaOtr(XS1,YS1, USE1, XA1,YA1,UAB1 ,XD1,YD1,P5);

DwaOtr(XA2,ZA2,UAB2, XK1,YK1,90 ,XD2,ZD2,P5);

P:=1; {прямая пересекается в точках

K(XK1,YK1,ZK2); D(XD1,YD1,ZD2}

end;

end;

end;

end;

 

Программное описание выполнено для решения частной задачи рис.23а. Программное описание для всей гаммы поверхностей (включая усеченные), основание которых расположено в плоскости, а образующие поверхности направлены в вершину, будет состоять из ряда подпрограмм и основной программы, содержащей выбор пути решения конкретной задачи.

 

 

Для непосредственного отображения пространства на экране монитора необходимы операторы линий чертежа и программы выполнения изделий по их параметрическому описанию.