lazarus-ccr/components/fpspreadsheet/source/common/fpspatterns.pas
wp_xxyyzz 3ece65fe51 fpspreadsheet: some clean-up
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9744 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2025-05-13 22:12:39 +00:00

637 lines
20 KiB
ObjectPascal

unit fpsPatterns;
{$mode objfpc}{$H+}
interface
uses
SysUtils, Classes, Contnrs, Math,
fpsTypes, fpsChart;
const
FPS_GRAY06 = 'GRAY06';
FPS_GRAY12 = 'GRAY12';
FPS_GRAY20 = 'GRAY20';
FPS_GRAY25 = 'GRAY25';
FPS_GRAY30 = 'GRAY30';
FPS_GRAY40 = 'GRAY40';
FPS_GRAY50 = 'GRAY50';
FPS_GRAY60 = 'GRAY60';
FPS_GRAY70 = 'GRAY70';
FPS_GRAY75 = 'GRAY75';
FPS_GRAY80 = 'GRAY80';
FPS_GRAY90 = 'GRAY90';
FPS_HOR_THICK = 'HOR_THICK';
FPS_VERT_THICK = 'VERT_THICK';
FPS_DIAG_UP_THICK = 'DIAG_UP_THICK';
FPS_DIAG_DOWN_THICK = 'DIAG_DOWN_THICK';
FPS_HATCH_THICK = 'HATCH_THICK';
FPS_CROSS_THICK = 'CROSS_THICK';
FPS_HOR_THIN = 'HOR_THIN';
FPS_VERT_THIN = 'VERT_THIN';
FPS_DIAG_UP_THIN = 'DIAG_UP_THIN';
FPS_DIAG_DOWN_THIN = 'DIAG_DOWN_THIN';
FPS_HATCH_THIN = 'HATCH_THIN';
FPS_CROSS_THIN = 'CROSS_THIN';
FPS_HOR_NARROW = 'HOR_NARROW';
FPS_VERT_NARROW = 'VERT_NARROW';
FPS_DIAG_UP_NARROW = 'DIAG_UP_NARROW';
FPS_DIAG_DOWN_NARROW = 'DIAG_DOWN_NARROW';
FPS_HATCH_NARROW = 'HATCH_NARROW';
FPS_CROSS_NARROW = 'CROSS_NARROW';
FPS_HOR_DASH = 'HOR_DASH';
FPS_VERT_DASH = 'VERT_DASH';
FPS_DIAG_UP_DASH = 'DIAG_UP_DASH';
FPS_DIAG_DOWN_DASH = 'DIAG_DOWN_DASH';
FPS_CROSS_DOT = 'CROSS_DOT';
FPS_HATCH_DOT = 'HATCH_DOT';
FPS_BRICK_HOR = 'BRICK_HOR';
FPS_BRICK_DIAG = 'BRICK_DIAG';
FPS_CHECKERBOARD_LARGE = 'CHECKERBOARD_LARGE';
FPS_CHECKERBOARD_SMALL = 'CHECKERBOARD_SMALL';
FPS_CONFETTI_LARGE = 'CONFETTI_LARGE';
FPS_CONFETTI_SMALL = 'CONFETTI_SMALL';
FPS_DIAMOND = 'DIAMOND';
FPS_DIVOT = 'DIVOT';
FPS_PLAID = 'PLAID';
FPS_SHINGLE = 'SHINGLE';
FPS_SPHERE = 'SPHERE';
FPS_TRELLIS = 'TRELLIS';
FPS_WAVE = 'WAVE';
FPS_WEAVE = 'WEAVE';
FPS_ZIGZAG = 'ZIGZAG';
type
TsLineFillPatternMultiplier = (lfpmSingle, lfpmDouble, lfpmTriple);
TsLineFillPattern = class
Distance: Single; // Distance of lines, in mm if > 0, in px if < 0
Angle: Single; // Rotation angle of pattern, in degrees
LineWidth: Single; // Line width of pattern, in mm if > 0, in px if < 0
Multiplier: TsLineFillPatternMultiplier;
end;
TsDotFillPattern = array[0..7] of Byte;
const
SOLID_DOT_FILL_PATTERN: TsDotFillPattern = ($FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF);
type
{ TsRawFillPattern
Combines the same visual pattern as a dot matrix and as vector strokes.
Vector strokes are supported only by ODS.
"Raw" patterns do not carry any color - this is added by TsChartFillPattern.
Used by charts only. }
TsRawFillPattern = class
private
FName: String;
FDotPattern: TsDotFillPattern;
FLinePattern: TsLineFillPattern;
procedure SetLinePattern(AValue: TsLineFillPattern);
public
constructor Create(AName: String; ADotPattern: TsDotFillPattern;
ALineDistance, ALineAngle, ALineWidth: Single; AMultiplier: TsLineFillPatternMultiplier);
constructor Create(AName: String; ADotPattern: TsDotFillPattern);
constructor Create(AName: String;
ALineDistance, ALineAngle, ALineWidth: Single; AMultiplier: TsLineFillPatternMultiplier);
destructor Destroy; override;
procedure CopyFrom(ASource: TsRawFillPattern); virtual;
property Name: String read FName;
property DotPattern: TsDotFillPattern read FDotPattern write FDotPattern;
property LinePattern: TsLineFillPattern read FLinePattern write SetLinePattern;
end;
TsRawFillPatternList = class(TFPObjectlist)
private
function GetItem(AIndex: Integer): TsRawFillPattern;
procedure SetItem(AIndex: Integer; AValue: TsRawFillPattern);
protected
function AddOrReplace(APattern: TsRawFillPattern): Integer;
function FindSimilarDotPattern(ALineDistance, ALineAngle, ALineWidth: Single;
AMultiplier: TsLineFillPatternMultiplier): TsDotFillPattern;
public
procedure AddBuiltinPatterns;
function AddFillPattern(AName: String; ADotPattern: TsDotFillPattern;
ALineDistance, ALineAngle, ALineWidth: Single; AMultiplier: TsLineFillPatternMultiplier): Integer;
function AddDotFillPattern(AName: String; APattern: TsDotFillPattern): Integer; overload;
function AddLineFillPattern(AName: String; ALineDistance, ALineAngle, ALineWidth: Single;
AMultiplier: TsLineFillPatternMultiplier): Integer;
function ClonePattern(AIndex: Integer; AName: String): Integer;
function FindByName(AName: String): TsRawFillPattern;
function FindLinePatternIndex(ALineDistance, ALineAngle, ALineWidth: Single;
AMultiplier: TsLineFillPatternMultiplier): Integer;
function IndexOfName(AName: String): Integer;
property Items[AIndex: Integer]: TsRawFillPattern read GetItem write SetItem; default;
end;
implementation
const
WIDE_DISTANCE = 3.0;
NARROW_DISTANCE = 1.5;
THIN_LINE = 0.1;
THICK_LINE = 0.3;
{$include fpspatterns_dotpatterns.inc}
function StringToDotPattern(APattern: String): TsDotFillPattern;
const
w = 8;
h = 8;
var
i, j, n, b: Integer;
begin
n := Length(APattern);
if n > w*h then
n := w*h;
FillChar(Result, Sizeof(Result), 0);
b := 0;
i := 0;
for j := 1 to n do
begin
if APattern[j] in ['x', 'X'] then
Result[i] := Result[i] or (1 shl b);
inc(b);
if b = w then
begin
inc(i);
b := 0;
end;
end;
end;
{ TsRawFillPattern }
constructor TsRawFillPattern.Create(AName: String; ADotPattern: TsDotFillPattern);
begin
inherited Create;
FName := AName;
FDotPattern := ADotPattern;
FLinePattern := nil; // no line pattern
end;
constructor TsRawFillPattern.Create(AName: String;
ALineDistance, ALineAngle, ALineWidth: Single; AMultiplier: TsLineFillPatternMultiplier);
begin
inherited Create;
FName := AName;
FDotPattern := SOLID_DOT_FILL_PATTERN;
FLinePattern := TsLineFillPattern.Create;
FLinePattern.Distance := ALineDistance;
FLinePattern.Angle := ALineAngle;
FLinePattern.LineWidth := ALineWidth;
FLinePattern.Multiplier := AMultiplier;
end;
constructor TsRawFillPattern.Create(AName: String; ADotPattern: TsDotFillPattern;
ALineDistance, ALineAngle, ALineWidth: Single; AMultiplier: TsLineFillPatternMultiplier);
begin
inherited Create;
FName := AName;
FDotPattern := ADotPattern;
FLinePattern := TsLineFillPattern.Create;
FLinePattern.Distance := ALineDistance;
FLinePattern.Angle := ALineAngle;
FLinePattern.LineWidth := ALineWidth;
FLinePattern.Multiplier := AMultiplier;
end;
destructor TsRawFillPattern.Destroy;
begin
FName := '';
FLinePattern.Free;
inherited;
end;
procedure TsRawFillPattern.CopyFrom(ASource: TsRawFillPattern);
begin
FName := ASource.Name;
FDotPattern := ASource.DotPattern;
SetLinePattern(ASource.LinePattern);
end;
procedure TsRawFillPattern.SetLinePattern(AValue: TsLineFillPattern);
begin
if AValue = nil then
begin
FLinePattern.Free;
FLinePattern := nil;
end else
begin
if FLinePattern = nil then
FLinePattern := TsLineFillPattern.Create;
FLinePattern.Distance := AValue.Distance;
FLinePattern.Angle := AValue.Angle;
FLinePattern.LineWidth := AValue.LineWidth;
FLinePattern.Multiplier := AValue.Multiplier;
end;
end;
(*
{ TsLineFillPatternStyle }
constructor TsLineFillPatternStyle.Create(AName: String;
ALineDistance, ALineAngle, ALineWidth: Single);
begin
inherited Create(AName);
FLineDistance := ALineDistance;
FLineAngle := ALineAngle;
FLineWidth := ALineWidth;
end;
procedure TsLineFillPatternStyle.CopyFrom(ASource: TsFillPatternStyle);
begin
if (ASource is TsLineFillPatternStyle) then
begin
FLineDistance := TsLineFillPatternStyle(ASource).LineDistance;
FLineAngle := TsLineFillPatternStyle(ASource).LineAngle;
FLineWidth := TsLineFillPatternStyle(ASource).LineWidth;
end;
inherited CopyFrom(ASource);
end;
// The pattern itself goes to infinity, limited by size of area to be filled.
function TsLineFillPatternStyle.GetHeight: Integer;
begin
Result := -1;
end;
function TsLineFillPatternStyle.GetWidth: Integer;
begin
Result := -1;
end;
{ TsDotFillPatternStyle }
constructor TsDotFillPatternStyle.Create(AName: String; APattern: String);
begin
inherited Create(AName);
StringToPattern(APattern);
end;
constructor TsDotFillPatternStyle.Create(AName: String; APattern: TBrushPattern);
begin
inherited Create(AName);
FPattern := APattern;
end;
procedure TsDotFillPatternStyle.CopyFrom(ASource: TsFillPatternStyle);
begin
if ASource is TsDotFillPatternStyle then
FPattern := TsDotFillPatternStyle(ASource).Pattern;
inherited CopyFrom(ASource);
end;
function TsDotFillPatternStyle.GetWidth: Integer;
begin
Result := SizeOf(TPenPattern);
end;
function TsDotFillPatternStyle.GetHeight: Integer;
begin
Result := SizeOf(TBrushPattern) div SizeOf(TPenPattern);
end;
procedure TsDotFillPatternStyle.StringToPattern(APattern: String);
var
L: TStrings;
w, h, i, j, x, y: Integer;
patt: String;
begin
L := TStringList.Create;
try
L.Text := APattern;
h := L.Count;
w := Length(L[0]);
for i := 1 to L.Count-1 do
if Length(L[i]) <> w then
raise Exception.Create('The lines in the pattern string must have the same lengths.');
FillChar(FPattern, Sizeof(FPattern), 0);
y := 0;
i := 0;
while y < SizeOf(TPenPattern) do
begin
if i >= L.Count then
i := 0;
patt := L[i];
x := 0;
j := 1;
while x < SizeOf(TPenPattern) do
begin
if j > w then
j := 1;
if (patt[j] in ['x', 'X']) then
FPattern[i] := FPattern[i] or (1 shl x);
inc(x);
inc(j);
end;
inc(y);
inc(i);
end;
finally
L.Free;
end;
end;
*)
{ TsRawFillPatternList }
{ Creates the built-in dot patterns as used by Excel. Not all of them are
available in ODS. }
procedure TsRawFillPatternList.AddBuiltinPatterns;
begin
fpsGray06 := AddDotFillPattern(FPS_GRAY06,
StringToDotPattern(GRAY06_PATTERN));
fpsGray12 := AddDotFillPattern(FPS_GRAY12,
StringToDotPattern(GRAY12_PATTERN));
fpsGray20 := AddDotFillPattern(FPS_GRAY20,
StringToDotPattern(GRAY20_PATTERN));
fpsGray25 := AddDotFillPattern(FPS_GRAY25,
StringToDotPattern(GRAY25_PATTERN));
fpsGray30 := AddDotFillPattern(FPS_GRAY30,
StringToDotPattern(GRAY30_PATTERN));
fpsGray40 := AddDotFillPattern(FPS_GRAY40,
StringToDotPattern(GRAY40_PATTERN));
fpsGray50 := AddDotFillPattern(FPS_GRAY50,
StringToDotPattern(GRAY50_PATTERN));
fpsGray60 := AddDotFillPattern(FPS_GRAY60,
StringToDotPattern(GRAY60_PATTERN));
fpsGray75 := AddDotFillPattern(FPS_GRAY75,
StringToDotPattern(GRAY75_PATTERN));
fpsGray80 := AddDotFillPattern(FPS_GRAY80,
StringToDotPattern(GRAY80_PATTERN));
fpsGray90 := AddDotFillPattern(FPS_GRAY90,
StringToDotPattern(GRAY90_PATTERN));
fpsHorThick := AddFillPattern(FPS_HOR_THICK,
StringToDotPattern(HOR_PATTERN_THICK),
WIDE_DISTANCE, 0.0, THICK_LINE, lfpmSingle);
fpsVertThick := AddFillPattern(FPS_VERT_THICK,
StringToDotPattern(VERT_PATTERN_THICK),
WIDE_DISTANCE, 90.0, THICK_LINE, lfpmSingle);
fpsDiagUpThick := AddFillPattern(FPS_DIAG_UP_THICK,
StringToDotPattern(DIAG_UP_PATTERN_THICK),
WIDE_DISTANCE, 45.0, THICK_LINE, lfpmSingle);
fpsDiagDownThick := AddFillPattern(FPS_DIAG_DOWN_THICK,
StringToDotPattern(DIAG_DOWN_PATTERN_THICK),
WIDE_DISTANCE, -45.0, THICK_LINE, lfpmSingle);
fpsHatchThick := AddFillPattern(FPS_HATCH_THICK,
StringToDotPattern(HATCH_PATTERN_THICK),
WIDE_DISTANCE, 45.0, THICK_LINE, lfpmDouble);
fpsCrossThick := AddFillPattern(FPS_CROSS_THICK,
StringToDotPattern(CROSS_PATTERN_THICK),
WIDE_DISTANCE, 0.0, THICK_LINE, lfpmDouble);
fpsHorThin := AddFillPattern(FPS_HOR_THIN,
StringToDotPattern(HOR_PATTERN_THIN),
WIDE_DISTANCE, 0.0, THIN_LINE, lfpmSingle);
fpsVertThin := AddFillPattern(FPS_VERT_THIN,
StringToDotPattern(VERT_PATTERN_THIN),
WIDE_DISTANCE, 90.0, THIN_LINE, lfpmSingle);
fpsDiagUpThin := AddFillPattern(FPS_DIAG_UP_THIN,
StringToDotPattern(DIAG_UP_PATTERN_THIN),
WIDE_DISTANCE, 45.0, THIN_LINE, lfpmSingle);
fpsDiagDownThin := AddFillPattern(FPS_DIAG_DOWN_THIN,
StringToDotPattern(DIAG_DOWN_PATTERN_THIN),
WIDE_DISTANCE, -45.0, THIN_LINE, lfpmSingle);
fpsHatchThin := AddFillPattern(FPS_HATCH_THIN,
StringToDotPattern(HATCH_PATTERN_THIN),
WIDE_DISTANCE, 45.0, THIN_LINE, lfpmDouble);
fpsCrossThin := AddFillPattern(FPS_CROSS_THIN,
StringToDotPattern(CROSS_PATTERN_THIN),
WIDE_DISTANCE, 0.0, THIN_LINE, lfpmDouble);
fpsHorNarrow := AddFillPattern(FPS_HOR_NARROW,
StringToDotPattern(HOR_PATTERN_NARROW),
NARROW_DISTANCE, 0.0, THIN_LINE, lfpmSingle);
fpsVertNarrow := AddFillPattern(FPS_VERT_NARROW,
StringToDotPattern(VERT_PATTERN_NARROW),
NARROW_DISTANCE, 90.0, THIN_LINE, lfpmSingle);
fpsDiagUpNarrow := AddFillPattern(FPS_DIAG_UP_NARROW,
StringToDotPattern(DIAG_UP_PATTERN_NARROW),
NARROW_DISTANCE, 45.0, THIN_LINE, lfpmSingle);
fpsDiagDownNarrow := AddFillPattern(FPS_DIAG_DOWN_NARROW,
StringToDotPattern(DIAG_DOWN_PATTERN_NARROW),
NARROW_DISTANCE, -45.0, THIN_LINE, lfpmSingle);
fpsHatchNarrow := AddFillPattern(FPS_HATCH_NARROW,
StringToDotPattern(HATCH_PATTERN_NARROW),
NARROW_DISTANCE, 45.0, THIN_LINE, lfpmDouble);
fpsCrossNarrow := AddFillPattern(FPS_CROSS_NARROW,
StringToDotPattern(CROSS_PATTERN_NARROW),
NARROW_DISTANCE, 0.0, THIN_LINE, lfpmDouble);
fpsHorDash := AddDotFillPattern(FPS_HOR_DASH,
StringToDotPattern(HOR_DASH_PATTERN));
fpsVertDash := AddDotFillPattern(FPS_VERT_DASH,
StringToDotPattern(VERT_DASH_PATTERN));
fpsDiagUpDash := AddDotFillPattern(FPS_DIAG_UP_DASH,
StringToDotPattern(DIAG_UP_DASH_PATTERN));
fpsDiagDownDash := AddDotFillPattern(FPS_DIAG_DOWN_DASH,
StringToDotPattern(DIAG_DOWN_DASH_PATTERN));
fpsCrossDot := AddDotFillPattern(FPS_CROSS_DOT,
StringToDotPattern(CROSS_PATTERN_DOT));
fpsHatchDot := AddDotFillPattern(FPS_HATCH_DOT,
StringToDotPattern(HATCH_PATTERN_DOT));
fpsBrickHor := AddDotFillPattern(FPS_BRICK_HOR,
StringToDotPattern(BRICK_HOR_PATTERN));
fpsBrickHor := AddDotFillPattern(FPS_BRICK_DIAG,
StringToDotPattern(BRICK_DIAG_PATTERN));
fpsCheckerBoardLarge := AddDotFillPattern(FPS_CHECKERBOARD_LARGE,
StringToDotPattern(CHECKERBOARD_LARGE_PATTERN));
fpsCheckerBoardSmall := AddDotFillPattern(FPS_CHECKERBOARD_SMALL,
StringToDotPattern(CHECKERBOARD_SMALL_PATTERN));
fpsConfettiLarge := AddDotFillPattern(FPS_CONFETTI_LARGE,
StringToDotPattern(CONFETTI_LARGE_PATTERN));
fpsConfettiSmall := AddDotFillPattern(FPS_CONFETTI_SMALL,
StringToDotPattern(CONFETTI_SMALL_PATTERN));
fpsDiamond := AddDotFillPattern(FPS_DIAMOND,
StringToDotPattern(DIAMOND_PATTERN));
fpsDivot := AddDotFillPattern(FPS_DIVOT,
StringToDotPattern(DIVOT_PATTERN));
fpsPlaid := AddDotFillPattern(FPS_PLAID,
StringToDotPattern(PLAID_PATTERN));
fpsShingle := AddDotFillPattern(FPS_SHINGLE,
StringToDotPattern(SHINGLE_PATTERN));
fpsSphere := AddDotFillPattern(FPS_SPHERE,
StringToDotPattern(SPHERE_PATTERN));
fpsTrellis := AddDotFillPattern(FPS_TRELLIS,
StringToDotPattern(TRELLIS_PATTERN));
fpsWave := AddDotFillPattern(FPS_WAVE,
StringToDotPattern(WAVE_PATTERN));
fpsWeave := AddDotFillPattern(FPS_WEAVE,
StringToDotPattern(WEAVE_PATTERN));
fpsZigzag := AddDotFillPattern(FPS_ZIGZAG,
StringToDotPattern(ZIGZAG_PATTERN));
end;
function TsRawFillPatternList.AddDotFillPattern(AName: String;
APattern: TsDotFillPattern): Integer;
var
patt: TsRawFillPattern;
begin
patt := TsRawFillPattern.Create(AName, APattern);
Result := AddOrReplace(patt);
end;
function TsRawFillPatternList.AddFillPattern(AName: String; ADotPattern: TsDotFillPattern;
ALineDistance, ALineAngle, ALineWidth: Single;
AMultiplier: TsLineFillPatternMultiplier): Integer;
var
patt: TsRawFillPattern;
begin
patt := TsRawFillPattern.Create(AName,
ADotPattern,
ALineDistance, ALineAngle, ALineWidth, AMultiplier
);
Result := AddOrReplace(patt);
end;
function TsRawFillPatternList.AddLineFillPattern(AName: String;
ALineDistance, ALineAngle, ALineWidth: Single;
AMultiplier: TsLineFillPatternMultiplier): Integer;
var
patt: TsRawFillPattern;
begin
patt := TsRawFillPattern.Create(AName, ALineDistance, ALineAngle, ALineWidth, AMultiplier);
patt.DotPattern := FindSimilarDotPattern(ALineDistance, ALineAngle, ALineWidth, AMultiplier);
Result := AddOrReplace(patt);
end;
function TsRawFillPatternList.AddOrReplace(APattern: TsRawFillPattern): Integer;
var
idx: Integer;
begin
idx := IndexOfName(APattern.Name);
if idx = -1 then
Result := Add(APattern)
else
begin
Items[idx].CopyFrom(APattern);
Insert(idx, APattern);
Result := idx;
end;
end;
{ Adds a copy of the pattern at the given index and gives it a new name. }
function TsRawFillPatternList.ClonePattern(AIndex: Integer; AName: String): Integer;
var
patt: TsRawFillPattern;
begin
patt := Items[AIndex];
Result := AddFillPattern(AName,
patt.DotPattern,
patt.LinePattern.Distance, patt.LinePattern.Angle, patt.LinePattern.LineWidth, patt.LinePattern.Multiplier
);
end;
function TsRawFillPatternList.FindByName(AName: String): TsRawFillPattern;
var
i: Integer;
begin
for i := 0 to Count-1 do
if Items[i].Name = AName then
begin
Result := Items[i];
exit;
end;
Result := nil;
end;
function TsRawFillPatternList.FindLinePatternIndex(
ALineDistance, ALineAngle, ALineWidth: Single;
AMultiplier: TsLineFillPatternMultiplier): Integer;
var
i: Integer;
patt: TsRawFillPattern;
begin
for i := 0 to Count-1 do
begin
patt := Items[i];
if patt.LinePattern = nil then
Continue;
if SameValue(ALineDistance, patt.LinePattern.Distance, 0.1) and
SameValue(ALineAngle, patt.LinePattern.Angle, 0.1) and
SameValue(ALineWidth, patt.LinePattern.LineWidth, 0.1) and
(AMultiplier = patt.LinePattern.Multiplier) then
begin
Result := i;
exit;
end;
end;
Result := -1;
end;
function TsRawFillPatternList.FindSimilarDotPattern(ALineDistance, ALineAngle,
ALineWidth: Single; AMultiplier: TsLineFillPatternMultiplier): TsDotFillPattern;
var
sinAngle, cosAngle: Single;
similarIdx: Integer;
singleLine: Boolean;
begin
similarIdx := -1;
SinCos(DegToRad(ALineAngle), sinAngle, cosAngle);
singleLine := (AMultiplier = lfpmSingle);
if SameValue(sinAngle, 0.0, 0.2) then // about +/- 12°
begin
if (ALineDistance >= WIDE_DISTANCE) or (ALineDistance <= -8) then
similarIdx := IfThen(singleLine, fpsHorThin, fpsCrossThin)
else
similarIdx := IfThen(singleLine, fpsHorNarrow, fpsCrossNarrow);
end else
if SameValue(cosAngle, 0.0, 0.2) then // about 90 +/- 12°
begin
if (ALineDistance >= WIDE_DISTANCE) or (ALineDistance <= -8) then
similarIdx := IfThen(singleLine, fpsVertThin, fpsCrossThin)
else
similarIdx := IfThen(singleLine, fpsVertNarrow, fpsCrossNarrow);
end else
if ALineAngle > 0 then
begin
if (ALineDistance >= WIDE_DISTANCE) or (ALineDistance <= -8) then
similarIdx := IfThen(singleLine, fpsDiagUpThin, fpsHatchThin)
else
similarIdx := IfThen(singleLine, fpsDiagUpNarrow, fpsHatchNarrow);
end else
begin
if (ALineDistance >= WIDE_DISTANCE) or (ALineDistance <= -8) then
similarIdx := IfThen(singleLine, fpsDiagDownThin, fpsHatchThin)
else
similarIdx := IfThen(singleLine, fpsDiagDownNarrow, fpsHatchNarrow);
end;
if similarIdx > -1 then
Result := Items[similarIdx].DotPattern
else
Result := SOLID_DOT_FILL_PATTERN;
end;
function TsRawFillPatternList.IndexOfName(AName: String): Integer;
begin
for Result := 0 to Count-1 do
if Items[Result].Name = AName then
exit;
Result := -1;
end;
function TsRawFillPatternList.GetItem(AIndex: Integer): TsRawFillPattern;
begin
Result := TsRawFillPattern(inherited Items[AIndex]);
end;
procedure TsRawFillPatternList.SetItem(AIndex: Integer; AValue: TsRawFillPattern);
begin
TsRawFillPattern(inherited Items[AIndex]).CopyFrom(AValue);
end;
end.