Реализовано с помощью алгоритма указанного на сайте
http://studentps.narod.ru/graph_kasy.html
Написание этого материала — это мой личный успех, небольшой прорыв и приобретение так нужных знаний.
Итак. Чтобы приступить к написанию программы, нужно определиться, что вообще потребуется. Надо размыслить над теми ситуациями когда касательную построить можно и когда нельзя. Мысленный анализ задачи должен привести к тому, что станет понятно: «Точка может лежать на окружности, внутри неё и на ней». Значит первым шагом будет написание программы, которая в зависимости от положения точки будет реагировать по разному. В принципе, написать отдельную функцию для этого несложно.
Вторая ступень развития — это изучение определений, чтение теории и поиск разных формул. При чтении теории нужно выкопать важную зацепку. Из определения касательных можно выцепить, что касательная окружности всегда перпендикулярна её радиусу. Теперь напрягаемся и увеличиваем силу мыслительных процессов. Если случится чудо и мозг проявит хоть какое-то содействие, то он может подсказать, что три точки — это треугольник, а если там есть перпендикуляр, то Теорема Пифагора. Но не всё так просто и если ваш мозг направил вас в это русло мыслительных рек, то он просто издевается над вами. Чертим на бумаге рисунок, убеждаемся в ошибке предположений и материм свой разум. Хорошо проматерившись на никчемность своей головы, прибегаем к поиску нахождения точек касания используя всю доступную литературу и интернет.
В процессе поиска находим разные способы и обдумываем можем ли мы применить хоть что-то из того что нарыли. Мозг в это время живет отдельно от нашего тела и думает о посторонних вещах, не желая помочь своему обладателю. Только чудо может спасти. Проявляем упорство и надеемся на удачу. В моем случае удача помогла найти способ определения точек касания через дополнительное построение окружности и я решил использовать это.
Как оказалось, вторая ступень вышла какой-то неожиданное напряженно-геморойной, но несмотря на это пришлось её преодолеть. Следующая ступенька — построение второй окружности и написание функций поиска пересечения точек. Эта ступень не такая тяжелая как вторая, но ели не знаем ничего, то приходится прибегать к поиску координат пересечения окружностей (где нарыл, сам не знаю, но нарыл в интернете). Несмотря на более легкое решение, оказывается тратим свое время и оставшиеся нервы. После построения второй окружности выводим обе окружности на экран. Отмечаем точку от которой строить касательную и проверяем линейкой верность. Если все правильно, то радуемся, что этот шаг был проще чем предыдущие.
Дальше идет этап, на котором нужно определится порядок построения (две или одну). Логически одну прямую построить проще, поэтому отталкиваемся от нее. На этой стадии вспоминаем то за что материли мозг. Касательная это перпендикуляр к радиусу. Прикидываем на листе бумаги и видим, что нужно построить перпендикуляр от радиуса. (честно говоря я еле смог придумать как строить перпендикулярные прямые по трем точкам), но если вы это читаете, то можете не изобретать велосипед, а просто проанализировать функцию для такого построения. Три точки есть (основная совпадает с точкой касания и еще центр окружности). функция написана (перпендикуляр можно построить по трем точкам, поэтому лучше использовать три параметра). В дальнейшем может проявится то, что знаменатели дроби могут быть нолями (я это не сразу заметил), поэтому это надо учесть и запомнить на будущее. (смотрите код)
После написания функции сразу тестируем ее правильность при различных положениях точки. Возникает ситуация — не можем положить точку на окружность в произвольном месте. Пытаемся применить формулу окружности. Наткнутся можно на разные и если пробуем применить общую формулу — снова материм мозг, будим соседа в 3 часа ночи, рвем волосы на своей голове, рвем волосы и на голове соседа из-за того что что-то не получается. Успокоившись пробуем тригонометрическую. Тригонометрическая должна помочь.
После всех мучений собираем воедино построение касательной если точка лежит на окружности.
Следующий шаг — построение прямых по двум точкам. Найти пример такого построения можно найти у меня в блоге.
Наводим красивости.
Код C++ Построить касательную к окружности
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
#include <stdlib.h> #include <iostream.h> #include <graphics.h> #include <math.h> struct Okr {double x,y,R;} O,A,M,Kas1,Kas2; //Собственный тип данных. Точка и окружность одновременно /*ФУНКЦИЯ ВЫВОДА ПРЯМОЙ ПО ДВУМ ТОЧКАМ*/ void pramaa(double x1,double y1,double x2,double y2) { double k=(y2-y1)/(x2-x1); //Угловой коэффициент double b=(x2*y1-x1*y2)/(x2-x1); //Смещение moveto(0,b); //Устанавливаем перо в начало рисования for (int x=0;x<getmaxx();x++) lineto(x,k*x+b); //Выводим прямую y=kx+b } /*ФУНКЦИЯ ПОИСКА ТОЧЕК КАСАНИЯ*/ void kasatelnie (double x1,double y1,double x2,double y2) { double R1=O.R; //Радиус основной окружности double R2=M.R; //Радиус вспомогательной окружности double D=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); //Длина отрезка от точки к центру основной окружности //это я фиг знает где взял double a=(R1*R1-R2*R2+D*D)/(2*D); double h=sqrt(R1*R1-a*a); double X=x1+a*(x2-x1)/D; double Y=y1+a*(y2-y1)/D; //Координаты первого касания Kas1.x=X+h*(y2-y1)/D; Kas1.y=Y-h*(x2-x1)/D; //Координаты второго касания Kas2.x=X-h*(y2-y1)/D; Kas2.y=Y+h*(x2-x1)/D; } /*ФУНКЦИЯ ПЕРПЕНДИКУЛЯРНЫХ ПРЯМЫХ ПО ТРЕМ ТОЧКАМ*/ void normal(double x1,double y1,double x2,double y2,double x3,double y3) { double k; if (x2!=x1) k=(y2-y1)/(x2-x1); //проверяем, чтоб знаменатель не оказался нулем float b=y3+1/k*x3; //если не ноль moveto(0,b); for (int x=0;x<getmaxx();x++) lineto(x,-1/k*x+b); //Рисуем прямую y=-1/kx+b if (y2==y1) for (int x=0;x<getmaxx();x++) lineto(x3,x); //При нулевом числителе вертиикаль if (x2==x1) for (int y=0;y<getmaxx();y++) lineto(y3,x); //При нулевом знаменателе горизонталь } /*ОПРЕДЕЛЕНИЕ МЕСТА ТОЧКИ ОТНОСИТЕЛЬНО ОКРУЖНОСТИ*/ int intersection(double x1,double y1,double x2,double y2) { //сначала я пытался использовать тип переменных double, но дублем считает не так как надо, поэтому флоат float d=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); //Расстояние от точки до окружности float b=O.R*O.R; //Квадрат радиуса (из упрощенной формулы окружности) if (d==b) return 1; //если квадрат радиуса равен квадрату длины отрезка, то одна точка касания else if (d<b) return 0; //если квадрат радиуса меньше квадрата длины отрезка, то нет точек return 2; //если не то и не другое = две точки касания } /*ФУНКЦИЯ ВВОДА ДАННЫХ*/ void input() { //основная окружность O.x=getmaxx()/2; O.y=getmaxy()/2; O.R=100; //Некоторая точка A.x=O.R*cos(M_PI)+O.x; //Это я клал точку на окружность, можно менять A.y=O.R*sin(M_PI)+O.y; //Можно менять //Расчет параметров вспомогательной окружности M.x=(A.x+O.x)/2; M.y=(A.y+O.y)/2; M.R=sqrt((A.x-O.x)*(A.x-O.x)+(A.y-O.y)*(A.y-O.y))/2; //Проверка числа точек и вывод касательных на экран if (intersection(A.x,A.y,O.x,O.y)==1) normal(O.x,O.y,O.x,O.y,A.x,A.y); //Если одна - чертим перпендикуляр else if (intersection(A.x,A.y,O.x,O.y)==2) //Если две - чертим прямую по двум точкам { kasatelnie(O.x,O.y,M.x,M.y); //Определяем положение точек касательных pramaa(A.x,A.y,Kas1.x,Kas1.y); //Первая прямая pramaa(A.x,A.y,Kas2.x,Kas2.y); //Вторая прямая } } void main() { int gd=DETECT,gm; initgraph(&gd,&gm,""); Kas1.x=Kas2.x=-10; //Просто, чтоб не смущали input(); // Ввод данных и расчеты //что-то типа придания красивого вида. fillellipse(A.x,A.y,3,3); outtextxy(A.x,A.y," A"); circle(O.x,O.y,O.R); fillellipse(O.x,O.y,2,2); outtextxy(O.x,O.y," O"); outtextxy(Kas1.x,Kas1.y," K1"); outtextxy(Kas2.x,Kas2.y," K2"); setfillstyle(1,1); fillellipse(Kas1.x,Kas1.y,3,3); fillellipse(Kas2.x,Kas2.y,3,3); cin.get(); closegraph(); return; } |
1 2 3 4 5 6 |
cout<<"Два числа. координата центра окружности через пробел"; cin>>O.x>>O.y; cout<<"Два числа. координата точки через которую проводить касательные"; cin>>A.x>>A.y; cout<<"Радиус окружности"; cin>>O.r; |
код не работает.