TAChart: Add range checks to TFitSeries. Issue #35175, modified patch by Marcin Wiazowski.

git-svn-id: trunk@60561 -
This commit is contained in:
wp 2019-03-02 18:50:34 +00:00
parent 71d732e388
commit 11d96908a0
2 changed files with 35 additions and 4 deletions

View File

@ -346,6 +346,7 @@ function InterpolateRGB(AColor1, AColor2: Integer; ACoeff: Double): Integer;
function IntToColorHex(AColor: Integer): String; inline; function IntToColorHex(AColor: Integer): String; inline;
function IsEquivalent(const A1, A2: Double): Boolean; inline; function IsEquivalent(const A1, A2: Double): Boolean; inline;
function IsNan(const APoint: TDoublePoint): Boolean; overload; inline; function IsNan(const APoint: TDoublePoint): Boolean; overload; inline;
function NameOrClassName(AComponent: TComponent): String; inline;
function NumberOr(ANum: Double; ADefault: Double = 0.0): Double; inline; function NumberOr(ANum: Double; ADefault: Double = 0.0): Double; inline;
function OrientToRad(AOrient: Integer): Double; inline; function OrientToRad(AOrient: Integer): Double; inline;
@ -500,6 +501,17 @@ begin
Result := IsNan(APoint.X) or IsNan(APoint.Y); Result := IsNan(APoint.X) or IsNan(APoint.Y);
end; end;
function NameOrClassName(AComponent: TComponent): String;
begin
if AComponent = nil then
Result := '<nil>'
else
if AComponent.Name = '' then
Result := AComponent.ClassName
else
Result := AComponent.Name;
end;
function NumberOr(ANum: Double; ADefault: Double): Double; function NumberOr(ANum: Double; ADefault: Double): Double;
begin begin
Result := IfThen(IsNan(ANum), ADefault, ANum); Result := IfThen(IsNan(ANum), ADefault, ANum);

View File

@ -504,6 +504,8 @@ const
DEF_PARAM_MIN = 0.0; DEF_PARAM_MIN = 0.0;
DEF_PARAM_MAX = 1.0; DEF_PARAM_MAX = 1.0;
SIndexOutOfRange = '[%s.%s] Index out of range.';
type type
TFitSeriesRange = class(TChartRange) TFitSeriesRange = class(TChartRange)
strict private strict private
@ -1699,7 +1701,8 @@ begin
fitSingular : Result := rsErrFitSingular; fitSingular : Result := rsErrFitSingular;
fitNoBaseFunctions : Result := rsErrFitNoBaseFunctions; fitNoBaseFunctions : Result := rsErrFitNoBaseFunctions;
else else
raise EChartError.CreateFmt('[TFitSeries.ErrorMsg] No message text assigned to error code #%d.', [ord(ErrCode)]); raise EChartError.CreateFmt('[%s.ErrorMsg] No message text assigned to error code #%d.',
[NameOrClassName(self), ord(ErrCode)]);
end; end;
end; end;
@ -1808,6 +1811,9 @@ procedure TFitSeries.GetConfidenceLimits(AIndex: Integer; out ALower, AUpper: Do
var var
val, sig, t: Double; val, sig, t: Double;
begin begin
if not InRange(AIndex, 0, ParamCount - 1) then
raise EChartError.CreateFmt(SIndexOutOfRange, [NameOrClassName(self), 'GetConfidenceLimits']);
if FState <> fpsValid then begin if FState <> fpsValid then begin
ALower := NaN; ALower := NaN;
AUpper := NaN; AUpper := NaN;
@ -1930,13 +1936,14 @@ end;
function TFitSeries.GetParam(AIndex: Integer): Double; function TFitSeries.GetParam(AIndex: Integer): Double;
begin begin
if not InRange(AIndex, 0, ParamCount - 1) then
raise EChartError.CreateFmt(SIndexOutOfRange, [NameOrClassName(Self), 'GetParam']);
if FState <> fpsValid then begin if FState <> fpsValid then begin
Result := NaN; Result := NaN;
exit; exit;
end; end;
if not InRange(AIndex, 0, ParamCount - 1) then
raise EChartError.Create('TFitSeries.GetParam index out of range');
if (FFitEquation in [feExp, fePower]) and (AIndex = 0) then if (FFitEquation in [feExp, fePower]) and (AIndex = 0) then
Result := exp(FFitParams[AIndex].Value) Result := exp(FFitParams[AIndex].Value)
else else
@ -1952,6 +1959,9 @@ function TFitSeries.GetParamError(AIndex: Integer): Double;
var var
val, sig: Double; val, sig: Double;
begin begin
if not InRange(AIndex, 0, ParamCount - 1) then
raise EChartError.CreateFmt(SIndexOutOfRange, [NameOrClassName(self), 'GetParamError']);
Result := NaN; Result := NaN;
if FState <> fpsValid then if FState <> fpsValid then
exit; exit;
@ -1969,6 +1979,9 @@ function TFitSeries.GetParam_pValue(AIndex: Integer): Double;
var var
t: Double; t: Double;
begin begin
if not InRange(AIndex, 0, ParamCount - 1) then
raise EChartError.CreateFmt(SIndexOutOfRange, [NameOrClassName(self), 'GetParam_pValue']);
t := GetParam_tValue(AIndex); t := GetParam_tValue(AIndex);
if IsNaN(t) then if IsNaN(t) then
Result := NaN Result := NaN
@ -1998,6 +2011,9 @@ function TFitSeries.GetParam_tValue(AIndex: Integer): Double;
var var
sig: Double; sig: Double;
begin begin
if not InRange(AIndex, 0, ParamCount - 1) then
raise EChartError.CreateFmt(SIndexOutOfRange, [NameOrClassName(self), 'GetParam_tValue']);
sig := GetParam_RawError(AIndex); sig := GetParam_RawError(AIndex);
if IsNaN(sig) then if IsNaN(sig) then
Result := NaN Result := NaN
@ -2123,6 +2139,9 @@ end;
procedure TFitSeries.SetFitBasisFunc(AIndex: TFitFuncIndex; AFitFunc: TFitFunc; procedure TFitSeries.SetFitBasisFunc(AIndex: TFitFuncIndex; AFitFunc: TFitFunc;
AFitFuncName: String); AFitFuncName: String);
begin begin
if not InRange(AIndex, 0, ParamCount - 1) then
raise EChartError.CreateFmt(SIndexOutOfRange, [NameOrClassName(self), 'SetFitBasisFunc']);
FFitParams[AIndex].CustomFunc := AFitFunc; FFitParams[AIndex].CustomFunc := AFitFunc;
FFitParams[AIndex].CustomFuncName := AFitFuncName; // e.g. 'sin(x)'; FFitParams[AIndex].CustomFuncName := AFitFuncName; // e.g. 'sin(x)';
end; end;
@ -2263,7 +2282,7 @@ begin
Add(255, 0, '', clWhite); Add(255, 0, '', clWhite);
end; end;
else else
raise Exception.Create('Palette not supported'); raise EChartError.CreateFmt('[%s.BuildPalette] Palette not supported', [NameOrClassName(Self)]);
end; end;
if FPaletteMin < FPaletteMax then begin if FPaletteMin < FPaletteMax then begin