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 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
| procedure DrawLineTer( BMP : TBitMap; xo,yo,xe,ye, epTrait : integer; CoulPen : TColor; TraceMode : tTraceMode; BoutsRonds : boolean);
type PCardinal = ^Cardinal;
var Theta,miEp,si,co,mis,mic,
ep,x,y,dx,dy,xo1,yo1,xe1,ye1,xo2,yo2,xe2,ye2,xorMin,xerMax,yorMin,yerMax,rr,d,u : Extended;
ap,bp,ad,bds,bdi,bdg,bdd : Extended;
iy,ix,iyp,ixp,yoMin,yeMax,xoMin,xeMax,r,i,j,xoc,xec,yoc,yec : integer;
// Le BitMap :
W,H : integer;
Scan0 : Integer; //Valeur du pointeur d'entrée dans le Bitmap.
Scan : Integer; //Pointeur temporaire destiné à être incrémenté.
MLS : Integer; //Memory Line Size (en bytes) du Bitmap.
Bpp : Integer; //Byte per pixel du Bitmap.
PixMin,PixMax : Integer; //Bornes de l'intervalle d'appartenance du pointeur au BitMap
pCoulPen: TRGBQuad; //Pointe sur la couleur du crayon
ymin1,ymax1,ymin2,ymax2,ymin,ymax : integer;
lignes : array of record xmin, xmax: Integer; end; // Le contour
Q : byte; // Les quadrants
procedure GSPixel;
begin Scan := Scan0;
Inc(Scan, iy*MLS + ix*Bpp);
if not ((Scan>=PixMin) and (Scan<=PixMax)) then EXIT; // Si on se trouve en-dehors de la mem du BMP
if not ((ix>=0) and (iy>=0) and (ix<=W-1) and (iy<=H-1)) then EXIT; // Si la droite dépasse les bords du Bmp
case TraceMode of
tmAffiche : if PRGBQuad(scan)^.rgbReserved = 0 then
PCardinal(scan)^ := not (PCardinal(scan)^ XOR coulPen);
tmEfface : if PRGBQuad(scan)^.rgbReserved = $FF then
PCardinal(scan)^ := not (PCardinal(scan)^ XOR coulPen);
else PRGBQuad(Scan)^:=pCoulPen; //<- pmCopy (utilisé uniquement lors d'un appel pour un tracé de finition)
end;
end; // GSPixel
procedure Rond(xc,yc,R : integer); // Embouts arrondis
var x,y : integer; e,u : Extended;
begin for y:=yc-R to yc+R do begin
e:=y-(yc-R); u:=sqrt(sqr(R)-sqr(R-e)); iy:=y;
for x:=xc-floor(u) to xc+floor(u) do begin ix:=x; GSPixel; end;
end;
end;
begin // INITIALISATION DES VARIABLES :
BMP.PixelFormat:=pf32bit; Bpp:=4; //<- vu que le code est du 32 bit pour le canal Alpha (si pf24bit alors Bpp:=3)
with pCoulPen do begin
pCoulPen.rgbBlue :=GetBValue(CoulPen);
pCoulPen.rgbGreen:=GetGValue(CoulPen);
pCoulPen.rgbRed :=GetRValue(CoulPen);
end;
Scan0 := Integer(BMP.ScanLine[0]);
MLS := Integer(BMP.ScanLine[1]) - Scan0; //Memory Line Size
W := BMP.Width ;
H := BMP.Height;
Bpp := Abs(MLS div W);
if Integer(BMP.ScanLine[H-1]) < Scan0 then begin //Si c'est un Bottom-Up DIB...
PixMin := Integer(BMP.ScanLine[H-1]);
PixMax := Scan0 + Bpp*W - Bpp;
end else begin //sinon c'est un Top-Down DIB...
PixMin := Scan0;
PixMax :=Integer(BMP.ScanLine[H-1]) + Bpp*W - Bpp;
end;
dx:=xe-xo; dy:=ye-yo;
miep:=epTrait/2; rr:=miEp; ep:=0;
if dx=0 then // Verticale
begin xo1:=xo - miep; xo2:=xo + miep; yo1:=min(yo,ye); ye1:=max(yo,ye);
for ix:=trunc(xo1) to trunc(xo2) do begin
// Embouts arrondis :
if BoutsRonds then begin
d:=abs(rr-ep); if rr>d then u:=sqrt(sqr(rr)-sqr(d)) else u:=0;
end else u:=0;
yoMin:=trunc(yo1-u); yeMax:=trunc(ye1+u);
// Tracé du segment incluant les prolongements pour embouts arrondis :
for iy:=yoMin to yeMax do GSPixel;
ep:=ep+1;
end;
EXIT;
end;
if ye=yo then // Horizontale
begin yo1:=yo - miep; yo2:=yo + miep; xo1:=min(xo,xe); xe1:=max(xo,xe);
for iy:=trunc(yo1) to trunc(yo2) do begin
// Embouts arrondis :
if BoutsRonds then begin
d:=abs(rr-ep); if rr>d then u:=sqrt(sqr(rr)-sqr(d)) else u:=0;
end else u:=0;
xoMin:=trunc(xo1-u); xeMax:=trunc(xe1+u);
// Tracé du segment incluant les prolongements pour embouts arrondis :
for ix:=xoMin to xeMax do GSPixel;
ep:=ep+1;
end;
EXIT;
end;
// Droites inclinées
try
Theta:=arcTan2(ye-yo,xe-xo); ad:=tan(Theta); // Pente de l'axe de la droite
si:=sin(Theta); co:=cos(Theta); mis:=miep*si; mic:=miep*co;
xo1:=xo + mis; yo1:=yo - mic; xo2:=xo - mis; yo2:=yo + mic;
xe1:=xe + mis; ye1:=ye - mic; xe2:=xe - mis; ye2:=ye + mic;
dy:=abs(ye-yo); dx:=abs(xe-xo);
Q:=0;
if (xe>xo) and (ye<yo) then Q:=1 else // Quadrants
if (xe<xo) and (ye<yo) then Q:=2 else
if (xe<xo) and (ye>yo) then Q:=3 else
if (xe>xo) and (ye>yo) then Q:=4;
bds:=yo1 - ad*xo1; // Ordonnée à l'origine du bord supérieur
bdi:=yo2 - ad*xo2; // Ordonnée à l'origine du bord inférieur
ap:=-1/ad; // Pente des petits côtés perpendiculaires
bdg:=-ap*xo1 + yo1; // Ordonnée à l'origine du bord gauche
bdd:=-ap*xe1 + ye1; // Ordonnée à l'origine du bord droit
ymin1:=min(round(ye1),round(yo2)); ymax1:=max(round(ye1),round(yo2));
ymin2:=min(round(ye2),round(yo1)); ymax2:=max(round(ye2),round(yo1));
ymin :=min(ymin1,ymin2); ymax :=max(ymax1,ymax2);
SetLength(lignes,ymax-ymin+2); // +2 sinon VA
for iy:=Low(lignes) to High(lignes) do begin
lignes[iy].xmin:=0; lignes[iy].xmax:=0;
end;
if BoutsRonds then begin // Embouts arrondis
Rond(xo,yo,round(miep)); Rond(xe,ye,round(miep));
end;
if dy>=dx then // Droites très inclinées par rapport à l'horizontale
begin // Les xmin et xmax :
yoMin:=round(min(yo1,ye1)); yeMax:=round(max(yo1,ye1));
for iy:=yoMin to yeMax do // x:= (y - b)/a
begin x:= (iy - bds)/ad; ix:=round(x);
case Q of
1,2 : lignes[iy-ymin].xmin:=ix;
3,4 : lignes[iy-ymin].xmax:=ix;
end
end;
xoMin:=round(min(xo1,xo2)); xeMax:=round(max(xo1,xo2));
for ix:=xoMin to xeMax do // y = a.x + b
begin y:=ap*ix + bdg; iy:=round(y);
case Q of
1,4 : lignes[iy-ymin].xmin:=ix;
2,3 : lignes[iy-ymin].xmax:=ix;
end;
end;
yoMin:=round(min(yo2,ye2)); yeMax:=round(max(yo2,ye2));
for iy:=yoMin to yeMax do // x:= (y - b)/a
begin x:= (iy - bdi)/ad; ix:=round(x);
case Q of
1,2 : lignes[iy-ymin].xmax:=ix;
3,4 : lignes[iy-ymin].xmin:=ix;
end;
end;
xoMin:=round(min(xe1,xe2)); xeMax:=round(max(xe1,xe2));
for ix:=xoMin to xeMax do // y = a.x + b
begin y:= ap*ix + bdd; iy:=round(y);
case Q of
1,4 : lignes[iy-ymin].xmax:=ix;
2,3 : lignes[iy-ymin].xmin:=ix;
end;
end;
// Eviter les xmin et xmax restés à 0 :
for iy:=1 to High(lignes) do begin
if lignes[iy].xmin=0 then lignes[iy].xmin:=lignes[iy-1].xmin;
if lignes[iy].xmax=0 then lignes[iy].xmax:=lignes[iy-1].xmax;
end;
if lignes[0].xmin=0 then lignes[0].xmin:=lignes[1].xmin;
if lignes[0].xmax=0 then lignes[0].xmax:=lignes[1].xmax;
// Tracé final :
for iy := ymin to ymax
do for ix:=lignes[iy-ymin].xmin to lignes[iy-ymin].xmax do GSPixel;
SetLength(lignes,1);
EXIT;
end else // Droites inclinées à moins de 45° par rapport à l'horizontale
begin // Les xmin et xmax :
xoMin:=round(min(xo1,xe1)); xeMax:=round(max(xo1,xe1));
for ix:=xoMin to xeMax do // y = a.x + b
begin y:= ad*ix + bds; iy:=round(y);
case Q of
1,2 : lignes[iy-ymin].xmin:=ix;
3,4 : lignes[iy-ymin].xmax:=ix;
end;
end;
yoMin:=round(min(yo1,yo2)); yeMax:=round(max(yo1,yo2));
for iy:=yoMin to yeMax do // x:= (y - b)/a
begin x:= (iy - bdg)/ap; ix:=round(x);
case Q of
1,4 : lignes[iy-ymin].xmin:=ix;
2,3 : lignes[iy-ymin].xmax:=ix;
end;
end;
xoMin:=round(min(xo2,xe2)); xeMax:=round(max(xo2,xe2));
for ix:=xoMin to xeMax do // y = a.x + b
begin y:= ad*ix + bdi; iy:=round(y);
case Q of
1,2 : lignes[iy-ymin].xmax:=ix;
3,4 : lignes[iy-ymin].xmin:=ix;
end;
end;
yoMin:=round(min(ye1,ye2)); yeMax:=round(max(ye1,ye2));
for iy:=yoMin to yeMax do // x:= (y - b)/a
begin x:= (iy - bdd)/ap; ix:=round(x);
case Q of
1,4 : lignes[iy-ymin].xmax:=ix;
2,3 : lignes[iy-ymin].xmin:=ix;
end;
end;
// Eviter les xmin et xmax restés à 0 :
for iy:=1 to High(lignes) do begin
if lignes[iy].xmin=0 then lignes[iy].xmin:=lignes[iy-1].xmin;
if lignes[iy].xmax=0 then lignes[iy].xmax:=lignes[iy-1].xmax;
end;
if lignes[0].xmin=0 then lignes[0].xmin:=lignes[1].xmin;
if lignes[0].xmax=0 then lignes[0].xmax:=lignes[1].xmax;
// Tracé final :
for iy := ymin to ymax
do for ix:=lignes[iy-ymin].xmin to lignes[iy-ymin].xmax do GSPixel;
SetLength(lignes,1);
end;
except
end;
end; // DrawLineTer |
Partager