mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-19 01:59:20 +02:00
fpvectorial: Improves the ellipse rendering
git-svn-id: trunk@33567 -
This commit is contained in:
parent
e05d507274
commit
5c6747acca
@ -15,11 +15,19 @@ unit fpvectorial;
|
||||
{$mode delphi}
|
||||
{$endif}
|
||||
|
||||
{$define USE_LCL_CANVAS}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Math,
|
||||
fpcanvas, fpimage;
|
||||
// FCL-Image
|
||||
fpcanvas, fpimage
|
||||
// LCL
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
, Graphics, LCLIntf, LCLType
|
||||
{$endif}
|
||||
;
|
||||
|
||||
type
|
||||
TvVectorialFormat = (
|
||||
@ -220,15 +228,19 @@ type
|
||||
|
||||
{@@
|
||||
}
|
||||
|
||||
{ TvEllipse }
|
||||
|
||||
TvEllipse = class(TvEntity)
|
||||
public
|
||||
// Mandatory fields
|
||||
MajorHalfAxis, MinorHalfAxis: Double;
|
||||
MajorHalfAxis: Double; // This half-axis is the horizontal one when Angle=0
|
||||
MinorHalfAxis: Double; // This half-axis is the vertical one when Angle=0
|
||||
{@@ The Angle is measured in degrees in relation to the positive X axis }
|
||||
Angle: Double;
|
||||
// Calculated fields
|
||||
BoundingRect: TRect;
|
||||
procedure CalculateBoundingRectangle;
|
||||
procedure CalculateBoundingBox(var ALeft, ATop, ARight, ABottom: Double); override;
|
||||
procedure Render(ADest: TFPCustomCanvas; ADestX: Integer = 0;
|
||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -421,6 +433,8 @@ function Make2DPoint(AX, AY: Double): T3DPoint;
|
||||
|
||||
implementation
|
||||
|
||||
uses fpvutils;
|
||||
|
||||
const
|
||||
Str_Error_Nil_Path = ' The program attempted to add a segment before creating a path';
|
||||
|
||||
@ -971,10 +985,15 @@ end;
|
||||
|
||||
{ TvEllipse }
|
||||
|
||||
procedure TvEllipse.CalculateBoundingRectangle;
|
||||
procedure TvEllipse.CalculateBoundingBox(var ALeft, ATop, ARight, ABottom: Double);
|
||||
var
|
||||
t, tmp: Double;
|
||||
begin
|
||||
// First do the trivial
|
||||
ALeft := X - MajorHalfAxis;
|
||||
ARight := X + MajorHalfAxis;
|
||||
ATop := Y - MinorHalfAxis;
|
||||
ABottom := Y + MinorHalfAxis;
|
||||
{
|
||||
To calculate the bounding rectangle we can do this:
|
||||
|
||||
@ -996,9 +1015,70 @@ begin
|
||||
=>
|
||||
tan(t) = b*cot(phi)/a
|
||||
}
|
||||
t := cotan(-MinorHalfAxis*tan(Angle)/MajorHalfAxis);
|
||||
tmp := X + MajorHalfAxis*cos(t)*cos(Angle) - MinorHalfAxis*sin(t)*sin(Angle);
|
||||
BoundingRect.Right := Round(tmp);
|
||||
if Angle <> 0.0 then
|
||||
begin
|
||||
t := cotan(-MinorHalfAxis*tan(Angle)/MajorHalfAxis);
|
||||
tmp := X + MajorHalfAxis*cos(t)*cos(Angle) - MinorHalfAxis*sin(t)*sin(Angle);
|
||||
ARight := Round(tmp);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TvEllipse.Render(ADest: TFPCustomCanvas; ADestX: Integer;
|
||||
ADestY: Integer; AMulX: Double; AMulY: Double);
|
||||
|
||||
function CoordToCanvasX(ACoord: Double): Integer;
|
||||
begin
|
||||
Result := Round(ADestX + AmulX * ACoord);
|
||||
end;
|
||||
|
||||
function CoordToCanvasY(ACoord: Double): Integer;
|
||||
begin
|
||||
Result := Round(ADestY + AmulY * ACoord);
|
||||
end;
|
||||
|
||||
var
|
||||
PointList: array[0..6] of TPoint;
|
||||
f: TPoint;
|
||||
dk, x1, x2, y1, y2: Integer;
|
||||
fx1, fy1, fx2, fy2: Double;
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ALCLDest: TCanvas absolute ADest;
|
||||
{$endif}
|
||||
begin
|
||||
CalculateBoundingBox(fx1, fy1, fx2, fy2);
|
||||
x1 := CoordToCanvasX(fx1);
|
||||
x2 := CoordToCanvasX(fx2);
|
||||
y1 := CoordToCanvasY(fy1);
|
||||
y2 := CoordToCanvasY(fy2);
|
||||
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
if Angle <> 0 then
|
||||
begin
|
||||
dk := Round(0.654 * Abs(y2-y1));
|
||||
f.x := Round(X);
|
||||
f.y := Round(Y - 1);
|
||||
PointList[0] := Rotate2DPoint(Point(x1, f.y), f, Angle) ; // Startpoint
|
||||
PointList[1] := Rotate2DPoint(Point(x1, f.y - dk), f, Angle);
|
||||
//Controlpoint of Startpoint first part
|
||||
PointList[2] := Rotate2DPoint(Point(x2- 1, f.y - dk), f, Angle);
|
||||
//Controlpoint of secondpoint first part
|
||||
PointList[3] := Rotate2DPoint(Point(x2 -1 , f.y), f, Angle);
|
||||
// Firstpoint of secondpart
|
||||
PointList[4] := Rotate2DPoint(Point(x2-1 , f.y + dk), f, Angle);
|
||||
// Controllpoint of secondpart firstpoint
|
||||
PointList[5] := Rotate2DPoint(Point(x1, f.y + dk), f, Angle);
|
||||
// Conrollpoint of secondpart endpoint
|
||||
PointList[6] := PointList[0]; // Endpoint of
|
||||
// Back to the startpoint
|
||||
ALCLDest.PolyBezier(Pointlist[0]);
|
||||
end
|
||||
else
|
||||
{$endif}
|
||||
begin
|
||||
ADest.Pen.Style := psSolid;
|
||||
ADest.Pen.FPColor := colBlack;
|
||||
ADest.Ellipse(x1, y1, x2, y2);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TsWorksheet }
|
||||
|
@ -37,56 +37,6 @@ procedure DrawFPVTextToCanvas(ASource: TvVectorialPage; CurText: TvText;
|
||||
|
||||
implementation
|
||||
|
||||
function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
|
||||
var
|
||||
sinus, cosinus : Extended;
|
||||
begin
|
||||
SinCos(alpha, sinus, cosinus);
|
||||
P.x := P.x - Fix.x;
|
||||
P.y := P.y - Fix.y;
|
||||
result.x := Round(p.x*cosinus + p.y*sinus) + fix.x ;
|
||||
result.y := Round(-p.x*sinus + p.y*cosinus) + Fix.y;
|
||||
end;
|
||||
|
||||
procedure DrawRotatedEllipse(
|
||||
ADest: TFPCustomCanvas;
|
||||
CurEllipse: TvEllipse;
|
||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||
var
|
||||
PointList: array[0..6] of TPoint;
|
||||
f: TPoint;
|
||||
dk, x1, x2, y1, y2: Integer;
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
ALCLDest: TCanvas absolute ADest;
|
||||
{$endif}
|
||||
begin
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
CurEllipse.CalculateBoundingRectangle();
|
||||
x1 := CurEllipse.BoundingRect.Left;
|
||||
x2 := CurEllipse.BoundingRect.Right;
|
||||
y1 := CurEllipse.BoundingRect.Top;
|
||||
y2 := CurEllipse.BoundingRect.Bottom;
|
||||
|
||||
dk := Round(0.654 * Abs(y2-y1));
|
||||
f.x := Round(CurEllipse.X);
|
||||
f.y := Round(CurEllipse.Y - 1);
|
||||
PointList[0] := Rotate2DPoint(Point(x1, f.y), f, CurEllipse.Angle) ; // Startpoint
|
||||
PointList[1] := Rotate2DPoint(Point(x1, f.y - dk), f, CurEllipse.Angle);
|
||||
//Controlpoint of Startpoint first part
|
||||
PointList[2] := Rotate2DPoint(Point(x2- 1, f.y - dk), f, CurEllipse.Angle);
|
||||
//Controlpoint of secondpoint first part
|
||||
PointList[3] := Rotate2DPoint(Point(x2 -1 , f.y), f, CurEllipse.Angle);
|
||||
// Firstpoint of secondpart
|
||||
PointList[4] := Rotate2DPoint(Point(x2-1 , f.y + dk), f, CurEllipse.Angle);
|
||||
// Controllpoint of secondpart firstpoint
|
||||
PointList[5] := Rotate2DPoint(Point(x1, f.y + dk), f, CurEllipse.Angle);
|
||||
// Conrollpoint of secondpart endpoint
|
||||
PointList[6] := PointList[0]; // Endpoint of
|
||||
// Back to the startpoint
|
||||
ALCLDest.PolyBezier(Pointlist[0]);
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
{@@
|
||||
This function draws a FPVectorial vectorial image to a TFPCustomCanvas
|
||||
descendent, such as TCanvas from the LCL.
|
||||
@ -388,11 +338,6 @@ begin
|
||||
CoordToCanvasY(CurCircle.Y + CurCircle.Radius)
|
||||
);
|
||||
end
|
||||
else if CurEntity is TvEllipse then
|
||||
begin
|
||||
CurEllipse := CurEntity as TvEllipse;
|
||||
DrawRotatedEllipse(ADest, CurEllipse);
|
||||
end
|
||||
else if CurEntity is TvCircularArc then
|
||||
begin
|
||||
CurArc := CurEntity as TvCircularArc;
|
||||
|
@ -46,6 +46,7 @@ procedure EllipticalArcToBezier(Xc, Yc, Rx, Ry, startAngle, endAngle: Double; va
|
||||
procedure CircularArcToBezier(Xc, Yc, R, startAngle, endAngle: Double; var P1, P2, P3, P4: T3DPoint);
|
||||
procedure AddBezierToPoints(P1, P2, P3, P4: T3DPoint; var Points: TPointsArray);
|
||||
procedure ConvertPathToPoints(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double; var Points: TPointsArray);
|
||||
function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
|
||||
// LCL-related routines
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
function ConvertPathToRegion(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double): HRGN;
|
||||
@ -273,6 +274,17 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function Rotate2DPoint(P,Fix :TPoint; alpha:double): TPoint;
|
||||
var
|
||||
sinus, cosinus : Extended;
|
||||
begin
|
||||
SinCos(alpha, sinus, cosinus);
|
||||
P.x := P.x - Fix.x;
|
||||
P.y := P.y - Fix.y;
|
||||
result.x := Round(p.x*cosinus + p.y*sinus) + fix.x ;
|
||||
result.y := Round(-p.x*sinus + p.y*cosinus) + Fix.y;
|
||||
end;
|
||||
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
function ConvertPathToRegion(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double): HRGN;
|
||||
var
|
||||
|
Loading…
Reference in New Issue
Block a user