Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Задачи _ Провести линию и ... две точки в одной подплоскости

Автор: DIMMUA 19.05.2007 2:36

Добрый день... У меня возникла маленькая неприятность, оказывется я не знаю как провести линию через две точки на весь экран. Т.е. я знаю как соеденить две точки линией и т д... Ну вот чтобы провести линию через эти две точки на весь экран я не знаю как это сделать. Может есть какая-то легкая процедура и т.д.?

К примеру: есть А(100,100) и B(200,200) - нужно провести через них линию

И еще, я так увлекся "украшательством" своей программы, что забыл про свое условие, короче у меня оврал, помогите: Есть уравнение прямой, есть две точки, прямая разбивает плоскость на подплоскости, нужно опеределать лежат ли эти две точки в разных. Уранение прямой разное, в общем виде: sx+ty+u=0 и точки (a,b) и (c,d). Т.е. a,b,c,d,s,t,u вводятся с клавиатуры.

Я прикрепил свой исходник.... Он еще не полность доделал... Немного о нем расскажу, чтобы было понятно: точки А,Б - обычные точки (вводите их около плюс-минус 10) точки X1 и X2 - точки из прямой, т.е. это две точки принадлежащие этой прямой. "Новые данные" - это идет "переработка" под вывод этих точек на координатной плоскости, например точка А(-2;1) - это А(280;220) - ну если учесть, что у меня точка (320;240) это центр, а одна "еденица" - это 20 пикселей.

Вообщем я должен построить прямую на весь экран, которая проходит через точки X1 и X2 и потом опередалеть лежит ли точки А и Б в одной подплоскости.

P.S. Если я что-то непонятно написал, вы спрашивайте...


Прикрепленные файлы
Прикрепленный файл  GRAFIK.PAS ( 1.69 килобайт ) Кол-во скачиваний: 190

Автор: мисс_граффити 19.05.2007 7:09

может, будет полезно
типы данных:

type
TPoint=record
x,y:integer;
end;
TLine=record
A,B,C:real; {Ax+By+C=0}
end;

алгоритмы:
  procedure InitLine(var L: TLine; pA,pB: TPoint);
begin
L.A:=pB.y-pA.y;
L.B:=pA.x-pB.x;
L.C:=pA.y*(pB.x-pA.x)-pA.x*(pB.y-pA.y);
end;

function SignPoint(L:TLine;P:TPoint):integer;
var r:real;
begin
r:=L.A*P.x+L.B*P.y+L.C;
if abs®<=0.001 then
SignPoint:=0
else
if r<0 then
SignPoint:=-1
else
SignPoint:=1;
end;

первая - создание линии по точкам
вторая - "знак" точки (как раз в какой полуплоскости лежит)

Автор: Michael_Rybak 19.05.2007 7:53

Если тебе не обязательно делать всё по-честному, можешь существенно выйти за пределы экрана.

Чтобы провести прямую, соединяющую точки Х1 и Х2, продли отрезок Х1-Х2 тысячекратно в обе стороны:

X1 + (X1-X2) * 1000 -> X2 + (X2-X1) * 1000

Понятно, что экран полностью пересечется.

Что касается вопроса про точки А и Б - нужно проверить, что ориентированные площади треугольников Х1Х2А и Х1Х2Б имеют одинаковый знак:

def OrientS(a, b, c) = (a.x-c.x)*(b.y-c.y) - (a.y-c.y)*(b.x-c.y)
return sign(OrientS(Х1, Х2, А)) = sign(OrientS(Х1, Х2, Б))

Автор: DIMMUA 19.05.2007 15:02

Спасибо, что ответили, кое что прояснилось... Правда я не все понял sad.gif
мисс_граффит это сильно сложно для меня, не мой уровень так сказать...

Michael_Rybak прочитал про ориантированную площадь треугольника, поискал в Инете, нашел такую формулу (твоя мне показалась сложной):

Ориентированная площадь S треугольника с вершинами P1, P2, P3:

. . . . | x1 y1 1 |
S = 1/2 | x2 y2 1 | = 1/2*[x1(y2-y3)+x2(y3-y1)+x3(y1-y2)]
. . . . | x3 y3 1 |


(точки поствил, что бы не смещалось)

У меня допустим точки P1, P2 - это точки X1 и X2, а в P3 я подставляю точку А и потом точку B. Попробовал, вроде все работает, если точки в разных подплоскоятх, то площади отличаются знаком.

Но вот насчет "продления" я не понял как это сделать.... Меня впринципе не интересует, где будут концы этого отрезка, главное чтобы он пересек экран (для наглядности). Можешь написать формулу продления отрезка более доходчиво для меня.

Автор: Lapp 19.05.2007 15:26

DIMMUA, ты выбрал не очень удачные названия точек, Х1 и Х2.. Можно я буду называть их M и N?
Так вот, предложение Michael_Rybak'а заключается в следующем..

Точки как бы представлены векторами, проведенными к ним из начала координат, назовем эти вектора так же, M и N. Тогда разность этих векторов представит сам отрезок:

а=M-N - вектор от точки N к точке M.
b=N-M - наоборот.

Рыбак предлагает умножить этот отрезок на 1000 и отложить, что получится, в обе стороны (продлить).
Тогда мы получим новые две точки, назовем их K и L :

K = M + а*1000
L = N + b*1000

Если расписать это все в координатах, получим:
Kx = Mx + (Mx-Nx)*1000
Ky = My + (My-Ny)*1000
Lx = Nx + (Nx-Mx)*1000
Ly = Ny + (Ny-My)*1000

Вот эти точки и соединяй оператором Line.
Теперь понятнее?

P.S.
DIMMUA, спасибо тебе за нормальную подробную постановку задачи с объяснениями и вежливый человеческий тон. Душа отдыхает в такой теме.. Просто хочется отвечать! smile.gif


Добавлено через 4 мин.
Хочу добавить, что мне метод Рыбака не очень по душе.. Так можно запросто вылететь за пределы диапазона целых чисел. Я бы предложил все же находить точное пересечение линии с границей экрана..

Автор: DIMMUA 19.05.2007 17:32

Lapp Спасибо! Все понял, даже получилось, скоро все доделаю, может еще что-то "красивее" сделаю и выложу исходник, может кому-то понадобится.

Щас правда как-то примитивно постараюсь ограничить, чтобы моя прамая не сильно вылазила за пределы экрана, а то и впраду за ошибку выдаст в самый неподходящий момент.

Автор: DIMMUA 19.05.2007 20:54

Программа получилась, все работает... В данный момент занимаюсь украшательством. Хотел сказать, что мне для выполнения этой задачи графика не нужна была, мы её в универе еще не изучали, поэтому у меня было столько вопросов. Кстати, а как вывести значение переменной на экран в графическом режиме? Например:

А(а;b) - и вот я пишу OutTextXY(10,10, ' A(',a,';',b,')'); - т.е. по типу как "writeln" - а оно выдает ошибку, я так понимаю этой функцией можно только текст вывести?

А какже тогда вывести значение какой-то переменной? Пробовал writeln - вообще не видно, что оно выводит, т.е. вроде как вывело, но ничего не видно. Пробовал менять цвет текста - ничего, правда в текстовом режиме цвет изменился.

P.S. Моя программа, наслаждайтесь... Знаю, для многих она покажется легкой, но для меня smile.gif

Фичи smile.gif программы:

1. Проверка пароля... и заметте вы не видите сам пароль при вводе. (пароль 1234567890)
2. Сделал ограничение, чтобы моя прямая не сильно вылазила за пределы экрана... т.е. я "умножаю" отрезок до тех пор, пока все вершины не скроются с экрана... Т.е. таким способом я врятли выйду за пределы integer.
3. В конце выводит время выполнения кода (кстати, взято с вашего сайта smile.gif )


Прикрепленные файлы
Прикрепленный файл  LAB16.PAS ( 4.91 килобайт ) Кол-во скачиваний: 192

Автор: Michael_Rybak 20.05.2007 2:54

Для вывода используй TextOut или OutText, уже не помню, как в Паскале.

Что касается выхода за диапазон - можно не умножать на 1000, а умножать на 2 до тех пор, пока за экран не выйдем. Так точно останемся в Integer.

Автор: DIMMUA 20.05.2007 15:22

Цитата(Michael_Rybak @ 19.05.2007 22:54) *

Для вывода используй TextOut или OutText, уже не помню, как в Паскале.

Что касается выхода за диапазон - можно не умножать на 1000, а умножать на 2 до тех пор, пока за экран не выйдем. Так точно останемся в Integer.


OutText или OutTextXY - это вывод обычного текста, а мне нужно вывести значение переменной. Например а=2, я пишу: OutTxet('a = ',a) - но паскаль выдает ошибку, он предлагает сделать OutText('a = '), т.е. я не могу вывести "а = 2" в графичеком режиме, а если написать writeln('a = ',a) - то этой надписи не видно (в графическом режиме).

Насчет выхода из диапазона я сделал так:
новые точки:=исходные*2 - если после этого, хоть одна точка остается в пределах экрана, то
новые точки:=исходные*3 - т.е. сначла пробую умножать на 2, потом на 3 и т.д....

Автор: Michael_Rybak 21.05.2007 6:21

Цитата(DIMMUA @ 20.05.2007 11:22) *

OutText или OutTextXY - это вывод обычного текста, а мне нужно вывести значение переменной. Например а=2, я пишу: OutTxet('a = ',a) - но паскаль выдает ошибку, он предлагает сделать OutText('a = '), т.е. я не могу вывести "а = 2" в графичеком режиме, а если написать writeln('a = ',a) - то этой надписи не видно (в графическом режиме).


Тогда переведи значение переменной в строку с помощью процедуры Str, и потом юзай OutText.

Цитата(DIMMUA @ 20.05.2007 11:22) *

Насчет выхода из диапазона я сделал так:
новые точки:=исходные*2 - если после этого, хоть одна точка остается в пределах экрана, то
новые точки:=исходные*3 - т.е. сначла пробую умножать на 2, потом на 3 и т.д....


Ага, молодец. Так тоже можно, просто лучше, имо, коэффициент увеличивать не линейно (2, 3, 4, 5, ..) а экспоненциально (2, 4, 8, 16, 32 ...) - быстрее вылезешь за экран smile.gif