Форум — Ответы     (  К темам )
 ?  Andrei: Как создать объект "ЛИНИЯ"? (31-12-2002 13:42:30)
Необходимо создать линию, которую можно было бы растягивать и перемещать, кликая по ней мышкой.
 Devnvd (31-12-2002 19:04:09)
Вот вам для затравки код рисования линий.
На форму Form1 положите TImage *Image1, сверху на Image1 наложите TPaintBox *PaintBox1. Размеры Image1 и PaintBox1 должны быть одинаковыми.
Image1 в примере служит контейнером для линий. Изображение в Image1 при этом хранится в виде метафайла, который является по сути списком того что вы на него рисуете.

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

Поиск линии для изменения её параметров делается чисто математически поиском ближайшей к месту вашего клика линии из списка. Обратите внимание, что уже начальный код занимает достаточно места. Я привёл здесь лишь набросок, а не руководство к написанию графического редактора.

//Параметры линии
int StartX,StartY;
int CurX,CurY;
TColor LineColor=clRed;
//Индикатор процесса формирования линии
bool idDrawLine=false;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Image1->Canvas->FillRect(Image1->ClientRect);
PaintBox1->BringToFront();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::PaintBox1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(Button !=mbLeft)return;
StartX=X; StartY=Y;
CurX=X; CurY=Y;
idDrawLine=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PaintBox1MouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(Button==mbLeft)
{
//Переносим изображение в контейнер Image1
if(StartX !=CurX ||StartY !=CurY)
{
TCanvas *Cv=Image1->Canvas;
Cv->Pen->Mode=pmCopy;
Cv->Pen->Color=LineColor;
Cv->MoveTo(StartX,StartY);
Cv->LineTo(CurX,CurY);
}
idDrawLine=false;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PaintBox1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
if(!idDrawLine)return;
TColor pencolor;
TPenMode penmode;
TCanvas *Cv=((TPaintBox *)Sender)->Canvas;
pencolor=Canvas->Pen->Color;
penmode=Canvas->Pen->Mode;
Cv->Pen->Mode=pmXor;
Cv->Pen->Color=clWhite;
//Подтираем старое изображение линии
if(StartX !=CurX ||StartY !=CurY)
{
Cv->MoveTo(StartX,StartY);
Cv->LineTo(CurX,CurY);
}
//Меняем координаты конца линии
CurX=X; CurY=Y;
// Рисуем новое изображение
if(StartX !=CurX ||StartY !=CurY)
{
Cv->MoveTo(StartX,StartY);
Cv->LineTo(CurX,CurY);
}
Cv->Pen->Color=pencolor;
Cv->Pen->Mode=penmode;
}
 Andrei (05-01-2003 11:34:02)
Спасибо за ответ.
Мне осталось непонятным, как осуществить математически поиск ближайшей линии:
то ли находить коэффицеты (y=kx+b) или создавать массив со всеми точками из которых состоит линия?
 Devnvd (06-01-2003 18:57:31)
Приведу выдержку из тестового примера. Если возникнут сложности, то могу выслать по почте полный проект примера. Пример был написан несколько для других целей, но в нём создаётся список линий и редактирование их.

// Поиск ближайшей к точке линии
double x,y,xg,yg,ax,ay,t,r,rmin,r0,r1;
double x0,y0,x1,y1;
double x00,y00,x11,y11,rt,rtt,r00,r11;
int i,j,k;
//Координаты точки (X,Y) можете перевести из пикселов
// в свою систему координат (xg,yg)
xg=X; yg=Y;
// Track список линий делаете как вам удобнее
rmin=10000.; //Радиус поиска ближайшей линии
j=-1;
for(i=0; i < TrackCount; i++)//Пробегаем по всем линиям
{
//Вытаскиваем параметры текущей линии из списка
if(Track[i]->Visible==0)continue; //Линия не нарисована
x0=Track[i]->StartX;
x1=Track[i]->EndX;
y0=Track[i]->StartY;
y1=Track[i]->EndY;
rt=pow(x1-x0,2)+ pow(y1-y0,2);
rt=sqrt(rt);
ax=(x1-x0)/rt;
ay=(y1-y0)/rt;
t=xg*ax+yg*ay-x0*ax-y0*ay;
x=x0+ax*t;
y=y0+ay*t;
r0=pow(x-x0,2)+pow(y-y0,2);
r0=sqrt(r0);
r1=pow(x-x1,2)+pow(y-y1,2);
r1=sqrt(r1);
if(r0> rt && r1> rt)continue;
r=pow(x-xg,2)+ pow(y-yg,2);
r=sqrt(r);
if(r> rmin)continue;
rmin=r;
r00=r0; r11=r1;rtt=rt;
x00=x0; y00=y0; x11=x1; y11=y1;
j=i;
}
if(j < 0)return;
// В результате:
// j — номер ближайшей линии из списка Track
// r00 — расстояние от линии до точки
// x00,y00,x11,y11 — координаты линии

 Andrei (23-01-2003 18:42:13)
Спасибо, я и пошел по этому пути
(нахождение кратчайшего расстояния от точки до отрезка).