multi.FillMode := fmWinding;
multi.FillMode := fillmode;
circular a écrit:Au sujet du FillMode, je vais regarder cela plus en détail. Cela est peut-être plus compliqué qu'il n'y parait parce que lorsque l'on dessine le contour du polygone, s'il revient sur lui-même on ne veut pas a priori que ce soit alterné. Est-ce que cela conviendrait d'avoir fmWinding pour le contour et la valeur fillmode pour le remplissage ?
Au sujet des hachures, il y a une fonction CreateBrushTexture qui est disponbile dans la classe TBGRABitmap ou bien dans l'unité BGRAPen. Elle s'accomode bien du mode répétition.
procedure TForm1.FormPaint(Sender: TObject);
var
p: TBGRAPath;
bmp: TBGRABitmap;
b: TBGRACustomBitmap;
begin
p := TBGRAPath.Create;
p.moveTo(40,180);
p.lineTo(200,20);
p.arc(200,180, 160, -Pi/2, 0, false);
p.closePath;
p.moveTo(200,150);
p.lineTo(330,120);
p.lineTo(200,50);
p.closePath;
bmp := TBGRABitmap.Create(ClientWidth,ClientHeight, BGRAWhite);
bmp.HorizLine(0,100,400, CSSSilver, dmSet);
b := bmp.CreateBrushTexture(bsFDiagonal, BGRABlack, BGRAPixelTransparent);
with bmp.Canvas2d do
begin
path(p);
strokeStyle(b);
fillStyle(CSSCyan);
lineWidth := 10;
strokeOverFill;
end;
b.Free;
bmp.Draw(Canvas,0,0);
bmp.Free;
end;
strokeStyle(CSSCyan);
fillStyle(b);
P.Fradin a écrit:Oui bien sûr, j'avais répondu trop vite, avant même d'essayer !
Merci en tout cas pour cet exemple qui m'a permis de résoudre plusieurs de mes soucis. Je pense que là j'obtiens ce que je voulais. La prochaine étape va être d'intégrer les remplissages avec gradients. J'ai toujours cette contrainte que les rendus dans les différents exports (pdf, svg, eps, pstricks, pgf) doivent être identiques (le plus possible en tout cas), et maintenant, grâce à ta librairie, je cherche aussi à ce que le dessin (provisoire) dans TeXgraph soit lui aussi identique !
PS : en lisant un peu le code, j'ai eu l'impression (je me trompe peut-être) que pour le calcul des courbes de Bézier tu n'utilises pas l'algorithme de Hörner (pour évaluer les expressions polynomiales) ?
function TCubicBezierCurve.ComputePointAt(t: single): TPointF;
var
f1,f2,f3,f4: single;
begin
f1 := (1-t);
f2 := f1*f1;
f1 *= f2;
f2 *= t*3;
f4 := t*t;
f3 := f4*(1-t)*3;
f4 *= t;
result.x := f1*p1.x + f2*c1.x +
f3*c2.x + f4*p2.x;
result.y := f1*p1.y + f2*c1.y +
f3*c2.y + f4*p2.y;
end;
bezier.p1.x := nouveau.x
bezier.p1 := PointF(x,y)
function TCubicBezierCurve.SimpleComputePoints(AAcceptedDeviation: single;
AIncludeFirstPoint: boolean = true): ArrayOfTPointF;
var
t,step: single;
i,nb: Integer;
a,b,c: TpointF; //<- ajout pour les coefficients
begin
nb := ComputeBezierCurvePrecision(p1,c1,c2,p2, AAcceptedDeviation/2);
if nb <= 1 then nb := 2;
a:=p2-p1+3*(c1-c2);
b:=3*(p1+c2)-6*c1;
c:=3*(c1-p1);
if AIncludeFirstPoint then
begin
setlength(result,nb);
result[0] := p1;
result[nb-1] := p2;
step := 1/(nb-1);
t := 0;
for i := 1 to nb-2 do
begin
t += step;
result[i] := p1+t*(c+t*(b+t*a)) // <- plus beson de ComputePointAt(t);
end;
end else
begin
setlength(result,nb-1);
result[nb-2] := p2;
step := 1/(nb-1);
t := 0;
for i := 0 to nb-3 do
begin
t += step;
result[i] := p1+t*(c+t*(b+t*a)) // <- plus beson de ComputePointAt(t);
end;
end;
end;
{Courbe de Bézier rationnelle quadratique quasi standard}
TRQuadraticBezierCurve = object(TQuadraticBezierCurve)
{** Weight of control point }
weight : single;
private
function SimpleComputePoints(AAcceptedDeviation: single = 0.1; AIncludeFirstPoint: boolean = true): ArrayOfTPointF;
public
function ComputePointAt(t: single): TPointF;
function ToPoints(AAcceptedDeviation: single = 0.1; AIncludeFirstPoint: boolean = true): ArrayOfTPointF;
end;
function BezierCurve(origin, control, destination: TPointF; Aweight:single) : TRQuadraticBezierCurve; overload;
function BezierCurve(origin, control, destination: TPointF; Aweight:single) : TRQuadraticBezierCurve;
begin
result.p1 := origin;
result.c := control;
result.p2 := destination;
result.weight := Aweight;
end;
function TRQuadraticBezierCurve.SimpleComputePoints(AAcceptedDeviation: single;
AIncludeFirstPoint: boolean = true): ArrayOfTPointF;
const precision = 1e-5;
var
t,step,len,den: single;
i,nb: Integer;
pA,pB,pC,c2 : TpointF;
a1,b1,c1:single;
begin
len := sqr(p1.x - c.x) + sqr(p1.y - c.y);
len := max(len, sqr(c.x - p2.x) + sqr(c.y - p2.y));
nb := round(sqrt(sqrt(len)/ AAcceptedDeviation));
//nb := ComputeBezierCurvePrecision(p1,c,c,p2, AAcceptedDeviation);
if nb <= 1 then nb := 2;
if AIncludeFirstPoint then
begin
setlength(result,nb);
result[0] := p1;
result[nb-1] := p2;
step := 1/(nb-1);
t := 0;
c1:=2*weight; c2:=c1*c;
pA:=p2+p1-c2; pB:=-2*p1+c2;
a1:=2-c1; b1:=-a1;
for i := 1 to nb-2 do
begin
t += step;
den := (1+t*(b1+t*a1));
if abs(den)>=precision then
result[i] := (p1+t*(pB+t*pA))*(1/den)
else
result[i] := EmptyPointF
end;
end else
begin
setlength(result,nb-1);
result[nb-2] := p2;
step := 1/(nb-1);
t := 0;
for i := 0 to nb-3 do
begin
t += step;
den := (1+t*(b1+t*a1));
if abs(den)>=precision then
result[i] := (p1+t*(pB+t*pA))*(1/den)
else
result[i] := EmptyPointF
end;
end;
end;
function TRQuadraticBezierCurve.ComputePointAt(t: single): TPointF;
const precision = 1e-5;
var
rev_t,f2,t2,den: single;
begin
rev_t := (1-t);
f2 := weight*rev_t*t*2;//le poids est sur le point de contrôle
rev_t *= rev_t;
t2 := t*t;
den := rev_t+f2+t2;
if abs(den)>=precision then
begin
result.x := (rev_t*p1.x + f2*c.x + t2*p2.x)/den;
result.y := (rev_t*p1.y + f2*c.y + t2*p2.y)/den;
end
else
result := EmptyPointF
end;
function TRQuadraticBezierCurve.ToPoints(AAcceptedDeviation: single;
AIncludeFirstPoint: boolean = true): ArrayOfTPointF;
begin
if weight=1 then
result := TQuadraticBezierCurve.ToPoints(AAcceptedDeviation, AIncludeFirstPoint)
else
result := SimpleComputePoints(AAcceptedDeviation, AIncludeFirstPoint)
end;
Revenir vers Version intermédiaire
Utilisateurs parcourant ce forum : Aucun utilisateur inscrit et 2 invités