Bonjour à tous
Je voudrais savoir comment calculer extraire les points de contrôles d'une courbe de bezier quadractique (et cubique serait un plus) à partir d'un tableau de N points pour dessiner une courbe de bezier continue. comme ci-dessous
Le but final de cette courbe est de me permettre de modifier les composantes RVB d'une image comme dans Gimp par exemple
J'ai chercher ici et sur le web, mais je n'ai pas trouvé de réponses compréhensible pour mon petit cerveau.
A l'heure actuelle (en pascal) voila ce que je sais faire avec un courbe de bezier quadratique (idem pour les cubique):
- Calculer la dérivée à un instant T :
Code Pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 function TBZ2DQuadraticBezierCurve.GetDerivativeAt(t : Single) : TBZFloatPoint; var f, tm, tm2 : Single; {$CODEALIGN VARMIN=16} t1,t2,t3 : TBZFloatPoint; {$CODEALIGN VARMIN=4} begin //dt(t) /t := P1 * (2t-2) + (2*P3-4*P2) * t + 2 * P2 tm := 1.0 - t; t1 := (FControlPoint - FStartPoint); t1 := (t1 + t1) * tm; t2 := (FEndPoint - FControlPoint); t2 := (t2 + t2) * t; Result := t1 + t2; end;- Calculer la normale à un instant T (et donc aussi extraire la tangente) :
Code Pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 function TBZ2DQuadraticBezierCurve.GetNormalAt(t : Single) : TBZFloatPoint; Var {$CODEALIGN VARMIN=16} dr : TBZFloatPoint; {$CODEALIGN VARMIN=4} begin dr := Self.getDerivativeAt(t); Dr := dr.Normalize; Result.X := -dr.Y; Result.Y := dr.X; end;- Calculer les coordonnées d'un point de la courbe à un instant T :
Code Pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 function TBZ2DQuadraticBezierCurve.ComputePointAt(t : single) : TBZFloatPoint; var t1,coef1,coef2,t2: single; begin t1:= 1-t; coef1 := t1 * t1; coef2 := t1 * (t + t); t2 := t*t; Result := (FStartPoint * Coef1) + (FControlPoint * Coef2) + (FEndPoint * t2); end;- Calculer les coordonnées des lignes constituant la courbe de bezier :
Code Pascal : Sélectionner tout - Visualiser dans une fenêtre à part
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 function TBZ2DQuadraticBezierCurve.ComputePolyLinePoints(Const nbStep : Integer) : TBZArrayOfFloatPoints; var nbSteps,i : Integer; Delta : Single; aTime : Single; {$CODEALIGN VARMIN=16} APoint : TBZFloatPoint; {$CODEALIGN VARMIN=4} Points : TBZArrayOfFloatPoints; begin if nbStep <= 0 then nbSteps := ComputeSteps(FTolerance) else nbSteps := nbStep; if nbSteps > 1 then begin Points := TBZArrayOfFloatPoints.Create(nbSteps+1); Delta := 1 / nbSteps; aTime := 0; For i := 0 to nbSteps-1 do begin APoint := ComputePointAt(aTime); Points.Add(APoint); aTime := aTime + Delta; end; Points.Add(FEndPoint); end else begin Points := TBZArrayOfFloatPoints.Create(1); Points.Add(FStartPoint); end; Result := Points; end;
Donc il faudrait que je puisse extraire les points de contrôles pour chaque courbe de bezier
Cela ne me semble pas compliqué (virtuellement) sachant que je doit en fait ajuster et décaler 2 points a chaque fois, mais il me manque quelque chose pour obtenir quelque chose de correcte.
J'ai tenté ceci :
ou :
- FControlPoints sont les points de contrôle de la courbe que je souhaite dessiner (de 2 à 32 points)
- FBezierControlPoints les points de contrôles intermédiaires calculés des courbes de bezier quadratique
Code Pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 procedure TBZCustomCurveEditor.UpdateBezierControlPoints; Var i, j : Integer; p1,p2, NewPt, delta1, Delta2 : TBZFloatPoint; begin j := 0; // Courbe ouverte for i := 0 to (FNbPoints[FSelectedChannel] - 2) do begin p1 := FControlPoints[FSelectedChannel, i].AsVector2f; p2 := FControlPoints[FSelectedChannel, i + 1].AsVector2f; Delta1 := p2 - p1; Delta2 := (Delta1 * 2) / 3; Delta1 := Delta1 / 3; NewPt := p1 + Delta1; FBezierControlPoints[FSelectedChannel, j] := NewPt; NewPt := p1 + Delta2; FBezierControlPoints[FSelectedChannel, j + 1] := NewPt; j := j + 2; end; end;
- FBezierAnchorPoints : ce sont les points d'ancrages (de fin) calculés d'une courbe de bezier quadratique
Code Pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 procedure TBZCustomCurveEditor.UpdateBezierAnchorPoints; var i, j : Integer; p1, p2, NewPt : TBZFloatPoint; begin FBezierAnchorPoints[FSelectedChannel,0] := FControlPoints[FSelectedChannel, 0].AsVector2f; FBezierAnchorPoints[FSelectedChannel,(FNbPoints[FSelectedChannel] - 1)] := FControlPoints[FSelectedChannel, (FNbPoints[FSelectedChannel] - 1)].AsVector2f; j := 1; for i := 1 to (FNbPoints[FSelectedChannel] - 2) do begin p1 := FControlPoints[FSelectedChannel, j].AsVector2f; p2 := FControlPoints[FSelectedChannel, j + 1].AsVector2f; NewPt := (p1 + p2) * 0.5; FBezierAnchorPoints[FSelectedChannel, i] := NewPt; j := j + 2; end; end;
et la méthode d'affichage :
Code Pascal : Sélectionner tout - Visualiser dans une fenêtre à part
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 procedure TBZCustomCurveEditor.DrawBezierCurve; Var i, j, k, l : Integer; BezierCurveTool : TBZ2DQuadraticBezierCurve; PolyLinePoints : TBZArrayOfFloatPoints; ptFrom, ptTo : TBZFloatPoint; begin j := 0; With FDisplayBuffer.Canvas do begin Antialias := True; Brush.Style := bsClear; Pen.Style := ssSolid; Pen.Color := clrRed; Pen.Width := 1; MoveTo(7,263); LineTo(263,7); end; for i := 0 to (FNbPoints[FSelectedChannel] - 1) do begin // /!\ NOTE : pour la 1ere courbe le premier point devrait-être FBezierAnchorPoints[FSelectedChannel, 0] BezierCurveTool := CreateQuadraticBezierCurve(FBezierControlPoints[FSelectedChannel, j], FBezierControlPoints[FSelectedChannel, j + 1], FBezierAnchorPoints[FSelectedChannel, i]); PolyLinePoints := BezierCurveTool.ComputePolyLinePoints(256); For l := 0 To 255 Do Begin PolyLinePoints.items[l] := PolyLinePoints.items[l].Clamp(0,255); end; FDisplayBuffer.Canvas.Pen.Color := clrRed; For l := 0 To 255 Do Begin k := (i + 1) Mod 256; if k=0 then Continue; FLUT[FSelectedChannel, l] := Round(PolyLinePoints.items[l].Y); ptFrom := PolyLinePoints.items[l]; ptTo := PolyLinePoints.items[k]; ptFrom.X := 7 + ptFrom.X; ptTo.X := 7 + ptTo.X; ptFrom.Y := 255 - ptFrom.Y + 7; ptTo.Y := 255 - ptTo.Y + 7; FDisplayBuffer.Canvas.Line(ptFrom, ptTo); end; FreeAndNil(PolyLinePoints); FreeAndNil(BezierCurveTool); j := j + 2; end; FDisplayBuffer.Canvas.Antialias := False; end;
Mais je me retrouve avec un affichage chaotique. Il y a quelque chose que j'ai raté.
Merci d'avance pour votre aide
Bonne journée
Jérôme
Partager