fpvectorial: Improves the ellipse rendering

git-svn-id: trunk@33567 -
This commit is contained in:
sekelsenmat 2011-11-16 14:12:55 +00:00
parent e05d507274
commit 5c6747acca
3 changed files with 101 additions and 64 deletions

View File

@ -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 }

View File

@ -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;

View File

@ -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