mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-16 02:20:30 +01:00
fpvectorial: More attempts at implementing support for elliptical arcs, not yet working
git-svn-id: trunk@41632 -
This commit is contained in:
parent
76cc6180d1
commit
5f6878bdb7
@ -230,6 +230,9 @@ type
|
||||
{ T2DEllipticalArcSegment }
|
||||
|
||||
T2DEllipticalArcSegment = class(T2DSegment)
|
||||
private
|
||||
E1, E2: T3DPoint;
|
||||
function AlignedEllipseCenterEquationT1(AParam: Double): Double;
|
||||
public
|
||||
RX, RY, XRotation: Double;
|
||||
LeftmostEllipse, ClockwiseArcFlag: Boolean;
|
||||
@ -1030,10 +1033,24 @@ end;
|
||||
|
||||
{ T2DEllipticalArcSegment }
|
||||
|
||||
function T2DEllipticalArcSegment.AlignedEllipseCenterEquationT1(
|
||||
AParam: Double): Double;
|
||||
var
|
||||
lLeftSide, lRightSide, lArg: Double;
|
||||
begin
|
||||
// E1.Y - RY*sin(t1) = E2.Y - RY*sin(arccos((- E1.X + RX*cos(t1) + E2.X)/RX))
|
||||
lLeftSide := E1.Y - RY*sin(AParam);
|
||||
lArg := (- E1.X + RX*cos(AParam) + E2.X)/RX;
|
||||
lRightSide := E2.Y - RY*sin(arccos(lArg));
|
||||
Result := lLeftSide - lRightSide;
|
||||
if Result < 0 then Result := -1* Result;
|
||||
end;
|
||||
|
||||
procedure T2DEllipticalArcSegment.CalculateCenter;
|
||||
var
|
||||
XStart, YStart, t: Double;
|
||||
XStart, YStart, lT1, lT2: Double;
|
||||
CX1, CY1, CX2, CY2, LeftMostX, LeftMostY, RightMostX, RightMostY: Double;
|
||||
RotatedCenter: T3DPoint;
|
||||
begin
|
||||
// Rotated Ellipse equation:
|
||||
// (xcosθ+ysinθ)^2 / RX^2 + (ycosθ−xsinθ)^2 / RY^2 = 1
|
||||
@ -1096,13 +1113,52 @@ begin
|
||||
X - A*Cos(t2) + C*Sin(t2) = XStart - A*sqrt(1-Sin(t1)^2) + C*Sin(t1)
|
||||
|
||||
}
|
||||
|
||||
// Solve by rotating everything to align the ellipse to the axises and then rotating back again
|
||||
E1 := Rotate3DPointInXY(Make3DPoint(XStart,YStart,0), Make3DPoint(0,0,0),-1*XRotation);
|
||||
E2 := Rotate3DPointInXY(Make3DPoint(X,Y,0), Make3DPoint(0,0,0),-1*XRotation);
|
||||
|
||||
// parametrized:
|
||||
// CX = E1.X - RX*cos(t1)
|
||||
// CY = E1.Y - RY*sin(t1)
|
||||
// CX = E2.X - RX*cos(t2)
|
||||
// CY = E2.Y - RY*sin(t2)
|
||||
//
|
||||
// E1.X - RX*cos(t1) = E2.X - RX*cos(t2)
|
||||
// E1.Y - RY*sin(t1) = E2.Y - RY*sin(t2)
|
||||
//
|
||||
// (- E1.X + RX*cos(t1) + E2.X)/RX = cos(t2)
|
||||
// arccos((- E1.X + RX*cos(t1) + E2.X)/RX) = t2
|
||||
//
|
||||
// E1.Y - RY*sin(t1) = E2.Y - RY*sin(arccos((- E1.X + RX*cos(t1) + E2.X)/RX))
|
||||
|
||||
// SolveNumerically
|
||||
|
||||
lT1 := SolveNumericallyAngle(AlignedEllipseCenterEquationT1, 0.0001, 20);
|
||||
|
||||
// CX = E1.X - RX*cos(t1)
|
||||
// CY = E1.Y - RY*sin(t1)
|
||||
CX1 := E1.X - RX*cos(lt1);
|
||||
CY1 := E1.Y - RY*sin(lt1);
|
||||
CX2 := E1.X - RX*cos(lt1+Pi);
|
||||
CY2 := E1.Y - RY*sin(lt1+Pi);
|
||||
|
||||
// Rotate back!
|
||||
RotatedCenter := Rotate3DPointInXY(Make3DPoint(CX1,CY1,0), Make3DPoint(0,0,0),XRotation);
|
||||
CX1 := RotatedCenter.X;
|
||||
CY1 := RotatedCenter.Y;
|
||||
RotatedCenter := Rotate3DPointInXY(Make3DPoint(CX2,CY2,0), Make3DPoint(0,0,0),XRotation);
|
||||
CX2 := RotatedCenter.X;
|
||||
CY2 := RotatedCenter.Y;
|
||||
|
||||
// errado!!!! Apagar quando achar o correto =(
|
||||
{
|
||||
CX := X - RX*Cos(0)*Cos(XRotation) + RY*Sin(0)*Sin(XRotation);
|
||||
CY := Y - RY*Sin(0)*Cos(XRotation) - RX*Cos(0)*Sin(XRotation);
|
||||
}
|
||||
|
||||
|
||||
// ativar quando tiver codigo pra calcular CX1, etc
|
||||
{
|
||||
if CX1 < CX2 then
|
||||
begin
|
||||
LeftMostX := CX1;
|
||||
@ -1127,7 +1183,7 @@ begin
|
||||
begin
|
||||
CX := RightMostX;
|
||||
CY := RightMostY;
|
||||
end;}
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure T2DEllipticalArcSegment.CalculateEllipseBoundingBox(ADest: TFPCustomCanvas;
|
||||
|
||||
@ -31,6 +31,8 @@ type
|
||||
T10Strings = array[0..9] of shortstring;
|
||||
TPointsArray = array of TPoint;
|
||||
|
||||
TNumericalEquation = function (AParameter: Double): Double of object; // return the error
|
||||
|
||||
// Color Conversion routines
|
||||
function FPColorToRGBHexString(AColor: TFPColor): string;
|
||||
function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
|
||||
@ -49,6 +51,9 @@ 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, RotCenter: TPoint; alpha:double): TPoint;
|
||||
function Rotate3DPointInXY(P, RotCenter: T3DPoint; alpha:double): T3DPoint;
|
||||
// Numerical Calculus
|
||||
function SolveNumericallyAngle(ANumericalEquation: TNumericalEquation;
|
||||
ADesiredMaxError: Double; ADesiredMaxIterations: Integer = 10): Double;
|
||||
// LCL-related routines
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
function ConvertPathToRegion(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double): HRGN;
|
||||
@ -309,6 +314,68 @@ begin
|
||||
end;
|
||||
|
||||
{$ifdef USE_LCL_CANVAS}
|
||||
|
||||
function SolveNumericallyAngle(ANumericalEquation: TNumericalEquation;
|
||||
ADesiredMaxError: Double; ADesiredMaxIterations: Integer = 10): Double;
|
||||
var
|
||||
lError, lErr1, lErr2, lErr3, lErr4: Double;
|
||||
lParam1, lParam2: Double;
|
||||
lIterations: Integer;
|
||||
lCount: Integer;
|
||||
begin
|
||||
lErr1 := ANumericalEquation(0);
|
||||
lErr2 := ANumericalEquation(Pi/2);
|
||||
lErr3 := ANumericalEquation(Pi);
|
||||
lErr4 := ANumericalEquation(3*Pi/2);
|
||||
|
||||
// Choose the place to start
|
||||
if (lErr1 < lErr2) and (lErr1 < lErr3) and (lErr1 < lErr4) then
|
||||
begin
|
||||
lParam1 := -Pi/2;
|
||||
lParam2 := Pi/2;
|
||||
end
|
||||
else if (lErr2 < lErr3) and (lErr2 < lErr4) then
|
||||
begin
|
||||
lParam1 := 0;
|
||||
lParam2 := Pi;
|
||||
end
|
||||
else if (lErr2 < lErr3) and (lErr2 < lErr4) then
|
||||
begin
|
||||
lParam1 := Pi/2;
|
||||
lParam2 := 3*Pi/2;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lParam1 := Pi;
|
||||
lParam2 := 2*Pi;
|
||||
end;
|
||||
|
||||
// Iterate as many times necessary to get the best answer!
|
||||
lCount := 0;
|
||||
lError := $FFFFFFFF;
|
||||
while ((ADesiredMaxError < 0 ) or (lError > ADesiredMaxError))
|
||||
and (lParam1 <> lParam2)
|
||||
and ((ADesiredMaxIterations < 0) or (lCount < ADesiredMaxIterations)) do
|
||||
begin
|
||||
lErr1 := ANumericalEquation(lParam1);
|
||||
lErr2 := ANumericalEquation(lParam2);
|
||||
|
||||
if lErr1 < lErr2 then
|
||||
lParam2 := (lParam1+lParam2)/2
|
||||
else
|
||||
lParam1 := (lParam1+lParam2)/2;
|
||||
|
||||
lError := Min(lErr1, lErr2);
|
||||
Inc(lCount);
|
||||
end;
|
||||
|
||||
// Choose the best of the last two
|
||||
if lErr1 < lErr2 then
|
||||
Result := lParam1
|
||||
else
|
||||
Result := lParam2
|
||||
end;
|
||||
|
||||
function ConvertPathToRegion(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double): HRGN;
|
||||
var
|
||||
WindingMode: Integer;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user