2011. február 1., kedd
How to draw an arc or ellipse with Bezier curves
Problem/Question/Abstract:
How to draw an arc or ellipse with Bezier curves
Answer:
Solve 1:
Example for painting an arc:
{Helper Function Draw Arc up to 90 degree}
procedure DrawArcWithBezier(ACanvas: TCanvas; CenterX, CenterY, RadiusX,
RadiusY, StartAngle, SweepRange: Double; UseMoveTo: Boolean = True);
type
TDoublePoint = record
x, y: Double;
end;
var
Coord: array[0..3] of TDoublePoint;
pts: array[0..3] of TPoint;
a, b, c, x, y: Double;
ss, cc: Double;
i: Integer;
{x, y = TDoublePoint}
function DPoint(x, y: Double): TDoublePoint;
begin
Result.x := x;
Result.y := y;
end;
begin
if SweepRange = 0 then
begin
if UseMoveTo then
ACanvas.MoveTo(Round(CenterX + RadiusX * cos(StartAngle)),
Round(CenterY - RadiusY * sin(StartAngle)));
ACanvas.LineTo(Round(CenterX + RadiusX * cos(StartAngle)),
Round(CenterY - RadiusY * sin(StartAngle)));
Exit;
end;
b := sin(SweepRange / 2);
c := cos(SweepRange / 2);
a := 1 - c;
x := a * 4 / 3;
y := b - x * c / b;
ss := sin(StartAngle + SweepRange / 2);
cc := cos(StartAngle + SweepRange / 2);
Coord[0] := DPoint(c, b);
Coord[1] := DPoint(c + x, y);
Coord[2] := DPoint(c + x, -y);
Coord[3] := DPoint(c, -b);
for i := 0 to 3 do
begin
pts[i] := Point(Round(CenterX + RadiusX * (Coord[i].x * cc + Coord[i].y * ss) - 0.0001), Round(Centery + RadiusY * (-Coord[i].x * ss + Coord[i].y * cc) - 0.0001));
end;
if UseMoveTo then
ACanvas.MoveTo(pts[0].x, pts[0].y);
ACanvas.PolyBezierTo([pts[1], pts[2], pts[3]]);
end;
{Draw Arc with Bezier curves}
function DrawArc(ACanvas: TCanvas; x1, y1, x2, y2, x3, y3, x4, y4: Integer): TPoint;
var
CenterX, CenterY: Double;
RadiusX, RadiusY: Double;
StartAngle, EndAngle, SweepRange: Double;
UseMoveTo: Boolean;
begin
CenterX := (x1 + x2) / 2;
CenterY := (y1 + y2) / 2;
RadiusX := (abs(x1 - x2) - 1) / 2;
RadiusY := (abs(y1 - y2) - 1) / 2;
if RadiusX < 0 then
RadiusX := 0;
if RadiusY < 0 then
RadiusY := 0;
StartAngle := ArcTan2(-(y3 - CenterY) * RadiusX, (x3 - CenterX) * RadiusY);
EndAngle := ArcTan2(-(y4 - CenterY) * RadiusX, (x4 - CenterX) * RadiusY);
SweepRange := EndAngle - StartAngle;
if SweepRange < 0 then
SweepRange := SweepRange + 2 * PI;
Result := Point(Round(CenterX + RadiusX * cos(StartAngle)),
Round(CenterY - RadiusY * sin(StartAngle)));
UseMoveTo := True;
while SweepRange > PI / 2 do
begin
DrawArcWithBezier(ACanvas, CenterX, CenterY, RadiusX, RadiusY, StartAngle, PI / 2, UseMoveTo);
SweepRange := SweepRange - PI / 2;
StartAngle := StartAngle + PI / 2;
UseMoveTo := False;
end;
if SweepRange >= 0 then
DrawArcWithBezier(ACanvas, CenterX, CenterY, RadiusX, RadiusY,
StartAngle, SweepRange, UseMoveTo);
end;
Solve 2:
This is the routine I use to convert a regular ellipse to a Bezier ellipse. It's in reals so you'll need to convert it if you are using an array of TPoint. Points[0] is the start(top left) of the ellipse and Points[2] is the finish(bottom right). The Points in this case are objects so if you are using array of TPoint remove the .AsPoint and replace RealPoint with Point. You'll also need to round some values.
{ ... }
const
Kappa = 0.5522847498;
var
dx, dy: single;
orgPt: TPoint;
begin
dx := (Points[2].x - Points[0].x) / 2;
dy := (Points[0].y - Points[2].y) / 2;
orgPt := RealPoint(Points[0].x + (dx), Points[0].y - (dy));
Points[0].AsPoint := RealPoint(orgPt.x - dx, orgPt.y);
Points[1].AsPoint := RealPoint(orgPt.x - dx, orgPt.y + (dy * Kappa));
Points[2].AsPoint := RealPoint(orgPt.x - (dx * Kappa), orgPt.y + dy);
Points[3].AsPoint := RealPoint(orgPt.x, orgPt.y + dy);
Points[4].AsPoint := RealPoint(orgPt.x + (dx * Kappa), orgPt.y + dy);
Points[5].AsPoint := RealPoint(orgPt.x + (dx), orgPt.y + (dy * Kappa));
Points[6].AsPoint := RealPoint(orgPt.x + dx, orgPt.y);
Points[7].AsPoint := RealPoint(orgPt.x + dx, orgPt.y - (dy * Kappa));
Points[8].AsPoint := RealPoint(orgPt.x + (dx * Kappa), orgPt.y - dy);
Points[9].AsPoint := RealPoint(orgPt.x, orgPt.y - dy);
Points[10].AsPoint := RealPoint(orgPt.x - (dx * Kappa), orgPt.y - dy);
Points[11].AsPoint := RealPoint(orgPt.x - dx, orgPt.y - (dy * Kappa));
Points[12].AsPoint := Points[0].AsPoint;
Points[13].AsPoint := Points[1].AsPoint;
Points[14].AsPoint := Points[2].AsPoint;
Points[15].AsPoint := Points[3].AsPoint;
end;
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése