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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
// 1 ) Pour détection de droites épaisses d'1 seul à plusieurs pixel(s)
// détection par calcul tenant compte de l'épaisseur du trait
// permet d'identifier une droite parmi d'autres de même couleur le cas échéant,
// et même de détecter une droite invisible à l'écran du tye limite de zone.
// 2 ) Pour déplacement de la droite par agrippage de la droite à la souris :
// - à moins de 15% d'une extrémité : déplacement par étirage-rotation
// - à plus de 15% d'une extrémité : déplacement parallèlement à elle-même
type TDroite = record
xo,yo, // coordonnées d'origine
xe,ye : integer; // coordonnées d'extrémité
coulTrait : TColor; // couleur du tracé
epTrait : Integer; // épaisseur du tracé
stylTrait : TPenStyle; // style du tracé si droite d'1 seul pixel
end;
TDroites = array [0..9] of TDroite;
var MesDroites : TDroites;
iDroiteSelectionnee, xMp,yMp : integer;
rOrigine : Extended; // ratio d'éloignement du point d'agripage par rapport à l'origine de la droite
procedure TForm1.FormShow(Sender: TObject);
var ep : byte;
begin color:=clWhite; //<pour tracés avec pmNotXor
iDroiteSelectionnee:=-1;
// 1) série de droites fines
ep:=1; // un seul pixel
with MesDroites[0] do
begin xo:=50; yo:=50; xe:=200; ye:=100;
coulTrait:=clRed; epTrait:=ep; stylTrait:=psSolid;
end;
with MesDroites[1] do // parallèle à la précédente et en contact avec celle-ci
begin xo:=50; yo:=51; xe:=200; ye:=101;
coulTrait:=clLime; epTrait:=ep; stylTrait:=psDash;
end;
with MesDroites[2] do
begin xo:=50; yo:=100; xe:=200; ye:=50;
coulTrait:=clNavy; epTrait:=ep; stylTrait:=psDot;
end;
with MesDroites[3] do // verticale
begin xo:=100; yo:=110; xe:=100; ye:=150;
coulTrait:=clGreen; epTrait:=ep; stylTrait:=psDashDot;
end;
with MesDroites[4] do // horizontale
begin xo:=100; yo:=110; xe:=50; ye:=110;
coulTrait:=clYellow; epTrait:=ep; stylTrait:=psDashDotDot;
end;
// 2) série de droites épaisses
ep:=10; // 10 pixels
with MesDroites[5] do
begin xo:=50; yo:=150; xe:=200; ye:=200;
coulTrait:=clRed; epTrait:=ep; stylTrait:=psSolid;
end;
with MesDroites[6] do // parallèle à la précédente et en contact avec celle-ci
begin xo:=50; yo:=161; xe:=200; ye:=211;
coulTrait:=clLime; epTrait:=ep; stylTrait:=psSolid;
end;
with MesDroites[7] do
begin xo:=50; yo:=200; xe:=200; ye:=150;
coulTrait:=clNavy; epTrait:=ep; stylTrait:=psSolid;
end;
with MesDroites[8] do // verticale
begin xo:=100; yo:=210; xe:=100; ye:=250;
coulTrait:=clGreen; epTrait:=ep; stylTrait:=psSolid;
end;
with MesDroites[9] do // horizontale
begin xo:=100; yo:=210; xe:=50; ye:=210;
coulTrait:=clYellow; epTrait:=ep; stylTrait:=psSolid;
end;
end;
procedure Trace( C : tCanvas; D : TDroite; mode : TPenMode);
begin with C do
begin pen.width := D.epTrait;
pen.color := D.coulTrait;
pen.Style := D.stylTrait;
pen.mode := mode;
moveto(D.xo, D.yo);
lineto(D.xe, D.ye);
pen.mode := pmCopy;
end;
end;
procedure TForm1.btnTracerDroitesClick(Sender: TObject);
var i : integer;
begin for i:=Low(MesDroites) to High(MesDroites)
do Trace(Canvas, MesDroites[i], pmNotXor); //pmCopy);
end;
function PointDansTronconDroite(xs,ys : integer; Droite : TDroite) : Extended;
//@param Result renvoie :
// -1 si le point xs,ys est en-dehors de la droite
// 2 si ce point est pile celui d'une doite réduite à un point
// et si xs,ys est situé sur le tronçon de la droite, renvoie une valeur
// comprise entre 0..1 et proportionnelle à l'éloignement de ce point
// par rapport à l'origine de la droite.
var a, b, miEp, lg : Extended; dx,dy,yc : integer; okx,oky : boolean;
begin Result:=-1;
miEp:=Droite.epTrait/2;
dx:=Droite.xe - Droite.xo;
dy:=Droite.ye - Droite.yo;
if (dx=0) and (dy=0) then // Droite réduite à 1 seul point
begin if (xs - miEp <=Droite.xo) and (Droite.xo <= xs + miEp)
and (ys - miEp <=Droite.yo) and (Droite.yo <= ys + miEp)
then Result:=2;
EXIT;
end;
okx:=False; oky:=False;
// okx et oky ne servent qu''à tester si le point-cible est situé entre
// l'origine et l'extrémité du tronçon et non dans ses prolongements
if ((dy<0) and (ys<=Droite.yo) and (ys>=Droite.ye))
or ((dy>0) and (ys<=Droite.ye) and (ys>=Droite.yo)) then oky:=True;
if ((dx>0) and (xs<=Droite.xe) and (xs>=Droite.xo))
or ((dx<0) and (xs<=Droite.xo) and (xs>=Droite.xe)) then okx:=True;
if (dx=0) then // Droite verticale
begin if (xs - miEp <=Droite.xo) and (Droite.xo <= xs + miEp)
and oky then Result:=(ys - Droite.yo)/dy;
EXIT;
end else
if (dy=0) then // Droite horizontale
begin if (ys - miEp <=Droite.yo) and (Droite.yo <= ys + miEp)
and okx then Result:=(xs - Droite.xo)/dx;
EXIT;
end else // Droite inclinée "y = a.x + b"
begin a:=dy/dx; // pente
b:=Droite.yo - a*Droite.xo;
yc:=round(a*xs + b); // y-calculé(xs)
lg:=sqrt(dx*dx + dy*dy); // longueur tronçon de droite
miEp:=abs(miEp*lg/dx); // projection de miEp sur la verticale yc-ys en xs
if (yc + miEp >= ys) and (yc - miEp <= ys)
and okx and oky then Result:=(xs - Droite.xo)/dx;
end;
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var i : integer;
begin i:=-1; iDroiteSelectionnee:=-1;
repeat inc(i); rOrigine:=PointDansTronconDroite(X,Y, MesDroites[i])
until (rOrigine>=0) or (i=High(MesDroites));
// ici on quitte la boucle dès qu'on a détecté la droite sur laquelle on cliqué
if rOrigine>=0
then begin labelTemoin.caption:=FloatToStr(rOrigine);
labelTemoin.color:=MesDroites[i].coulTrait;
iDroiteSelectionnee:=i;
Screen.Cursor := crHandPoint;
xMp:=X; yMp:=Y;
end
else begin labelTemoin.color:=clBtnFace;
labelTemoin.caption:=FloatToStr(rOrigine);
end;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
var i,dxs,dys : integer;
begin i:=iDroiteSelectionnee;
if i>=0 then
begin dxs:=X - xMp; dys:=Y - yMp;
with MesDroites[i] do
begin Trace(Canvas, MesDroites[i], pmNotXor);
if rOrigine<=0.15 then // Etirage droite par agrippage près de l''origine
begin xo:=xo+dxs; yo:=yo+dys; end else
if rOrigine>=0.85 then // Etirage droite par agrippage près de l''extrémité
begin xe:=xe+dxs; ye:=ye+dys; end
else // Déplacement droite parallèle à elle-même
begin xo:=xo+dxs; yo:=yo+dys; xe:=xe+dxs; ye:=ye+dys; end;
Trace(Canvas, MesDroites[i], pmNotXor);
end;
xMp:=X; yMp:=Y;
end;
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin iDroiteSelectionnee:=-1;
Screen.Cursor := crDefault;
end; |
Partager