Консультация № 184346
29.10.2011, 16:38
214.89 руб.
0 25 1
Здравствуйте!
Нужна помощь с написанием программы (Delphi 7, оконный режим).
Задача такая: в программу вводятся (вручную) координаты множества точек на плоскости (x,y). Пожелание: можно реализовать через отдельную форму, где в Edit-ы забиваются координаты x и y, а затем они заносятся, допустим, в StringGrid, находящийся на этой же отдельной форме.
Нужно найти радиус и координаты центра окружности, которая проходит как минимум через три точки введенного множества точек и содержит внутри наибольшее количество точек из этого множества. Нарисовать эту окружность на форме (через Canvas), а также отобразить на форме все точки множества с учетом масштаба. Методы реализации, интерфейс, оформление - на ваше усмотрение.
Очень надеюсь на помощь. Заранее спасибо.

Обсуждение

давно
Профессор
230118
3054
29.10.2011, 22:55
общий
А сколько приблизительно будет точек? Если немного, можно сделать перебором, а если нет, это будет слишком долго и нужен другой алгоритм.
Неизвестный
30.10.2011, 02:59
общий
Адресаты:
Думаю, можно для небольшого количества (4-8 точек).
Неизвестный
30.10.2011, 08:26
общий
Ой, забыла совсем: еще помимо того, что на форме нужно нарисовать окружность и точки, желательно бы еще отобразить оси координат xOy (тоже с учетом масштаба и имеющихся точек). Но так как в задании это я забыла указать, это тоже пожелание.
давно
Мастер-Эксперт
425
4118
30.10.2011, 10:44
общий
А количество точек фиксировано или задаётся пользователем?
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
30.10.2011, 11:09
общий
Количество точек задается пользователем, то есть сколько он координат (x,y) введет, столько и получится точек. Но ввода большого количества точек не предполагается.
Неизвестный
14.11.2011, 14:19
общий
Есть какие-нибудь шансы на успех?
Неизвестный
14.11.2011, 14:52
общий
Адресаты:
Вы всё еще планируете дать ответ?
давно
Профессор
230118
3054
15.11.2011, 04:44
общий
Да, продлите пожалуйста еще на 1 день.
Неизвестный
17.11.2011, 12:39
общий
Вас сроки не поджимают?
Неизвестный
17.11.2011, 12:57
общий
Нет, без проблем) Пока не срочно.
Неизвестный
17.11.2011, 13:04
общий
ХорошоТогда подождём ответа от Асмик. Если у неё так и не сложится, я сама напишу программу на следующей неделе.
давно
Профессионал
304622
583
23.11.2011, 14:27
общий
Я может быть изображу что-нибудь.
Неизвестный
23.11.2011, 15:38
общий
Как успехи? :)
давно
Профессионал
304622
583
23.11.2011, 16:49
общий
А обязательно использовать Canvas?

В Delphi tсть готовый инструмент -- TChart. Там проще.
Вот пример.
(Здесь задача пока упрощённая -- строится окружность для самых удалённых точек. Надо ещё перебор сделать.)
давно
Профессионал
304622
583
24.11.2011, 00:48
общий
Вот в общих чертах. Выбор точек для окружности -- прямым перебором. Не стал пока додумывать каких-то оптимальных алгоритмов. Не уверен, что они есть. Если устраивает -- сделаю комментарии и занесу в ответы.

Программа

[code h=200]
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, StdCtrls, ExtCtrls, TeEngine, Series, TeeProcs, Chart;

type
TForm1 = class(TForm)
xy: TStringGrid;
LabelXc: TLabel;
LabelYc: TLabel;
LabelR: TLabel;
NewX: TLabeledEdit;
NewY: TLabeledEdit;
Button1: TButton;
Chart1: TChart;
Series1: TLineSeries;
Series2: TLineSeries;
Series3: TLineSeries;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

var x:array[1..3] of real;
y:array[1..3] of real;
xc,yc,R:real;

procedure GetCenter;
var a:real;
begin
a:=x[3]*2*y[1] - x[3]*2*y[2] - x[2]*2*y[1] + x[2]*2*y[2]
- x[2]*2*y[2] + x[2]*2*y[3] + x[1]*2*y[2] - x[1]*2*y[3];
if abs(a)<1e-10
then begin
xc:=0;
yc:=0;
R:=0;
end
else begin
yc:=(
x[2]*sqr(x[3]) + x[2]*sqr(y[3]) - x[2]*sqr(x[2]) - x[2]*sqr(y[2])
- x[1]*sqr(x[3]) - x[1]*sqr(y[3]) + x[1]*sqr(x[2]) + x[1]*sqr(y[2])
- x[3]*sqr(x[2]) - x[3]*sqr(y[2]) + x[3]*sqr(x[1]) + x[3]*sqr(y[1])
+ x[2]*sqr(x[2]) + x[2]*sqr(y[2]) - x[2]*sqr(x[1]) - x[2]*sqr(y[1])
)/a;

if x[2]-x[1]<>0
then
xc:=(sqr(x[2]) + sqr(y[2]) - sqr(x[1]) - sqr(y[1])
+ 2*yc*y[1] - 2*yc*y[2]
)/2/(x[2]-x[1])
else
xc:=(sqr(x[3]) + sqr(y[3]) - sqr(x[2]) - sqr(y[2])
+ 2*yc*y[2] - 2*yc*y[3]
)/2/(x[3]-x[2]);

R:=sqrt(sqr(y[1]-yc)+sqr(x[1]-xc));
end;
end;

type point= record
x,y:real;
end;

var p:array of point;

procedure TForm1.FormCreate(Sender: TObject);
begin
xy.ColCount:=2;
xy.RowCount:=2;
xy.FixedCols:=0;
xy.FixedRows:=1;
xy.Cells[0,0]:='X';
xy.Cells[1,0]:='Y';
randomize;
end;

procedure TForm1.Button1Click(Sender: TObject);
var i,j,k,l,n,ibest,jbest,kbest,nbest:integer;
xxx,yyy:real;
begin
xy.Cells[0,xy.RowCount-1]:=NewX.Text;
xy.Cells[1,xy.RowCount-1]:=NewY.Text;
xy.RowCount:=xy.RowCount+1;
SetLength(p,length(p)+1);
p[High(p)].x:=StrToFloat(NewX.Text);
p[High(p)].y:=StrToFloat(NewY.Text);


if length(p)>=3
then begin
nbest:=-1;
for i:=0 to High(p) do
for j:=i+1 to High(p) do
for k:=j+1 to High(p) do
begin
x[1]:=p[i].x;
x[2]:=p[j].x;
x[3]:=p[k].x;
y[1]:=p[i].y;
y[2]:=p[j].y;
y[3]:=p[k].y;
GetCenter;
n:=0;
for l:=0 to High(p) do
if (l<>i) and (l<>j) and (l<>k)
and (sqr(p[l].x-xc)+sqr(p[l].y-yc)<sqr(R))
then inc(n);
if n>nbest
then begin
nbest:=n;
ibest:=i;
jbest:=j;
kbest:=k;
end;
end;

x[1]:=p[ibest].x;
x[2]:=p[jbest].x;
x[3]:=p[kbest].x;
y[1]:=p[ibest].y;
y[2]:=p[jbest].y;
y[3]:=p[kbest].y;
GetCenter;
LabelXc.Caption:='Xc = ' + FloatToStrF(xc,ffFixed,0,3);
LabelYc.Caption:='Yc = ' + FloatToStrF(yc,ffFixed,0,3);
LabelR.Caption:='R = ' + FloatToStrF(R,ffFixed,0,3);

Chart1.Series[2].Clear;
Chart1.Series[2].AddXY(p[ibest].x,p[ibest].y);
Chart1.Series[2].AddXY(p[jbest].x,p[jbest].y);
Chart1.Series[2].AddXY(p[kbest].x,p[kbest].y);

Chart1.Series[0].Clear;
for i:=0 to 2000 do
begin
xxx:=xc+R*cos(i/2000*2*pi);
yyy:=yc+R*sin(i/2000*2*pi);
Chart1.Series[0].AddXY(xxx,yyy);

end;
end;

Chart1.Series[1].Clear;
for i:=0 to High(p) do
if (i<>ibest) and (i<>jbest) and (i<>kbest)
then Chart1.Series[1].AddXY(p[i].x,p[i].y);

NewX.Text:=FloatToStrF(random,ffFixed,0,5);
NewY.Text:=FloatToStrF(random,ffFixed,0,5);
end;

end.
[/code]
давно
Профессионал
304622
583
24.11.2011, 00:50
общий
Пока использовано TChart вместо Canvas. Если надо Canvas -- пишите.
Неизвестный
24.11.2011, 04:09
общий
Адресаты:
Спасибо! Буду пока разбираться с программой. Но, к сожалению, все же нужен canvas, задание так дано.
давно
Профессионал
304622
583
24.11.2011, 12:05
общий
Будет.
давно
Профессионал
304622
583
24.11.2011, 21:56
общий
Не было времени сегодня. Продлите до завтрашнего вечера.
давно
Профессионал
304622
583
25.11.2011, 13:41
общий
это ответ
Здравствуйте, Mechenaya!

Готово. Вычисление параметров окружности сделано примерно, как здесь. Но там ошибка в выкладках. Выбор комбинации точек -- простым перебором. Остальное в комментариях. Пишите вопросы.
Прикрепленные файлы:
5
Неизвестный
25.11.2011, 14:20
общий
Адресаты:
Спасибо большое! Сейчас разбираюсь в программе. Единственный на данный момент вопрос: возможно ли построить оси координат (чтобы при добавлении новой точки они масштабировались). Это можно реализовать? Просто оси xOy, без каких-либо надписей.
давно
Профессионал
304622
583
25.11.2011, 15:10
общий
Это можно реализовать? Просто оси xOy, без каких-либо надписей.


Легко. Для оси OX, например, надо нарисовать линию: по координате X -- от края до края экрана, т.ею от 0 до gr.Width; координата Y в области вывода равна 0, т.е. вычисляется по той же формуле: round(ky*(yc - ymin)). При желании от правого конца можно ещё стрелочку пририсовать. Аналогично OX.

Попробуйте. Если не получится -- пишите.

чтобы при добавлении новой точки они масштабировались


Рисунок каждый раз стирается и рисуется заново. Так что это само собой.
Неизвестный
25.11.2011, 16:27
общий
25.11.2011, 16:28
Адресаты:
При выполнении программы получается такое (на примере):

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

То получаем, что точка (-1,-1) располагается на месте, на котором должна была бы быть точка (-1,1) - то есть по оси Y значение инвертируется.
Кроме осей, в программу ничего не добавляла. Почему получается такая "инверсия" значений Y?
С осями вроде разобралась, рисуются так:
Код:

gr.Canvas.Pen.Color:=clBlack;
gr.Canvas.Pen.Width:=2;
gr.Canvas.MoveTo(0,round(ky*(-ymin)));
gr.Canvas.LineTo(gr.width,round(ky*(-ymin)));
gr.Canvas.MoveTo(round(kx*(-xmin)),0);
gr.Canvas.LineTo(round(kx*(-xmin)),gr.height);
давно
Профессионал
304622
583
25.11.2011, 21:14
общий
25.11.2011, 21:16
Почему получается такая "инверсия" значений Y?


Совсем забыл -- вертикальная-то ось на экране с верху вниз идёт!! (Т.е. (0,0) -- это левый верхний угол.) Должно быть
Код:

yy:=gr.Height - round(ky*(yc - ymin))

Во всех местах где вычисляется yy.

С осями вроде разобралась, рисуются так:


Да, конечно. Только Y исправить.
Неизвестный
26.11.2011, 05:12
общий
Адресаты:
Все, теперь нормально работает. Спасибо! Больше вопросов не имею.
Форма ответа