mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-03 00:17:18 +01:00
TAChart: Use records to pass parameters to GetNearestPoint function
git-svn-id: trunk@32072 -
This commit is contained in:
parent
d0faffd601
commit
cc324e9e04
@ -31,6 +31,17 @@ const
|
||||
DEF_AXIS_INDEX = -1;
|
||||
|
||||
type
|
||||
TNearestPointParams = record
|
||||
FDistFunc: TPointDistFunc;
|
||||
FPoint: TPoint;
|
||||
end;
|
||||
|
||||
TNearestPointResults = record
|
||||
FImg: TPoint;
|
||||
FIndex: Integer;
|
||||
FValue: TDoublePoint;
|
||||
end;
|
||||
|
||||
{ TCustomChartSeries }
|
||||
|
||||
TCustomChartSeries = class(TBasicChartSeries)
|
||||
@ -80,9 +91,8 @@ type
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function GetNearestPoint(
|
||||
ADistFunc: TPointDistFunc; const APoint: TPoint;
|
||||
out AIndex: Integer; out AImg: TPoint; out AValue: TDoublePoint): Boolean;
|
||||
virtual;
|
||||
const AParams: TNearestPointParams;
|
||||
out AResults: TNearestPointResults): Boolean; virtual;
|
||||
function GetParentComponent: TComponent; override;
|
||||
procedure GetSingleLegendItem(AItems: TChartLegendItems);
|
||||
function HasParent: Boolean; override;
|
||||
@ -223,9 +233,8 @@ type
|
||||
public
|
||||
procedure Assign(ASource: TPersistent); override;
|
||||
function GetNearestPoint(
|
||||
ADistFunc: TPointDistFunc; const APoint: TPoint;
|
||||
out AIndex: Integer; out AImg: TPoint; out AValue: TDoublePoint): Boolean;
|
||||
override;
|
||||
const AParams: TNearestPointParams;
|
||||
out AResults: TNearestPointResults): Boolean; override;
|
||||
procedure MovePoint(var AIndex: Integer; const ANewPos: TPoint); override;
|
||||
property MarkPositions: TLinearMarkPositions
|
||||
read FMarkPositions write SetMarkPositions default lmpOutside;
|
||||
@ -340,13 +349,13 @@ begin
|
||||
end;
|
||||
|
||||
function TCustomChartSeries.GetNearestPoint(
|
||||
ADistFunc: TPointDistFunc; const APoint: TPoint; out AIndex: Integer;
|
||||
out AImg: TPoint; out AValue: TDoublePoint): Boolean;
|
||||
const AParams: TNearestPointParams;
|
||||
out AResults: TNearestPointResults): Boolean;
|
||||
begin
|
||||
Unused(ADistFunc, APoint);
|
||||
AIndex := 0;
|
||||
AImg := Point(0, 0);
|
||||
AValue := ZeroDoublePoint;
|
||||
Unused(AParams);
|
||||
AResults.FIndex := 0;
|
||||
AResults.FImg := Point(0, 0);
|
||||
AResults.FValue := ZeroDoublePoint;
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
@ -896,8 +905,8 @@ begin
|
||||
end;
|
||||
|
||||
function TBasicPointSeries.GetNearestPoint(
|
||||
ADistFunc: TPointDistFunc; const APoint: TPoint;
|
||||
out AIndex: Integer; out AImg: TPoint; out AValue: TDoublePoint): Boolean;
|
||||
const AParams: TNearestPointParams;
|
||||
out AResults: TNearestPointResults): Boolean;
|
||||
var
|
||||
dist, minDist, i: Integer;
|
||||
pt: TPoint;
|
||||
@ -909,14 +918,13 @@ begin
|
||||
// measured in screen coordinates. With high zoom ratios this may lead to
|
||||
// an integer overflow, so ADistFunc should use saturation arithmetics.
|
||||
pt := Point(GetXImgValue(i), GetYImgValue(i));
|
||||
dist := ADistFunc(APoint, pt);
|
||||
dist := AParams.FDistFunc(AParams.FPoint, pt);
|
||||
if dist >= minDist then
|
||||
continue;
|
||||
minDist := dist;
|
||||
AIndex := i;
|
||||
AImg := pt;
|
||||
AValue.X := GetXValue(i);
|
||||
AValue.Y := GetYValue(i);
|
||||
AResults.FIndex := i;
|
||||
AResults.FImg := pt;
|
||||
AResults.FValue := DoublePoint(GetXValue(i), GetYValue(i));
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -82,8 +82,8 @@ type
|
||||
|
||||
procedure Draw(ADrawer: IChartDrawer); override;
|
||||
function GetNearestPoint(
|
||||
ADistFunc: TPointDistFunc; const APoint: TPoint; out AIndex: Integer;
|
||||
out AImg: TPoint; out AValue: TDoublePoint): Boolean; override;
|
||||
const AParams: TNearestPointParams;
|
||||
out AResults: TNearestPointResults): Boolean; override;
|
||||
function IsEmpty: Boolean; override;
|
||||
public
|
||||
property DomainExclusions: TIntervalList read FDomainExclusions;
|
||||
@ -489,25 +489,24 @@ begin
|
||||
AItems.Add(TLegendItemLine.Create(Pen, Title));
|
||||
end;
|
||||
|
||||
function TFuncSeries.GetNearestPoint(ADistFunc: TPointDistFunc;
|
||||
const APoint: TPoint; out AIndex: Integer; out AImg: TPoint;
|
||||
out AValue: TDoublePoint): Boolean;
|
||||
function TFuncSeries.GetNearestPoint(
|
||||
const AParams: TNearestPointParams;
|
||||
out AResults: TNearestPointResults): Boolean;
|
||||
var
|
||||
t: Double;
|
||||
dummy: Integer = 0;
|
||||
begin
|
||||
Unused(ADistFunc);
|
||||
Result := false;
|
||||
AIndex := -1;
|
||||
AResults.FIndex := -1;
|
||||
if OnCalculate = nil then exit;
|
||||
// Instead of true nearest point, just calculate the function at the cursor.
|
||||
with GraphToAxis(ParentChart.ImageToGraph(APoint)) do begin
|
||||
with GraphToAxis(ParentChart.ImageToGraph(AParams.FPoint)) do begin
|
||||
t := X;
|
||||
if DomainExclusions.Intersect(t, t, dummy) then exit;
|
||||
AValue.X := X;
|
||||
AResults.FValue.X := X;
|
||||
end;
|
||||
OnCalculate(AValue.X, AValue.Y);
|
||||
AImg := ParentChart.GraphToImage(AxisToGraph(AValue));
|
||||
OnCalculate(AResults.FValue.X, AResults.FValue.Y);
|
||||
AResults.FImg := ParentChart.GraphToImage(AxisToGraph(AResults.FValue));
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
|
||||
@ -265,9 +265,8 @@ type
|
||||
|
||||
procedure Draw(ADrawer: IChartDrawer); override;
|
||||
function GetNearestPoint(
|
||||
ADistFunc: TPointDistFunc;
|
||||
const APoint: TPoint; out AIndex: Integer; out AImg: TPoint;
|
||||
out AValue: TDoublePoint): Boolean; override;
|
||||
const AParams: TNearestPointParams;
|
||||
out AResults: TNearestPointResults): Boolean; override;
|
||||
procedure MovePoint(var AIndex: Integer; const ANewPos: TPoint); override;
|
||||
|
||||
published
|
||||
@ -654,24 +653,23 @@ begin
|
||||
AItems.Add(TLegendItemLine.Create(Pen, Title));
|
||||
end;
|
||||
|
||||
function TConstantLine.GetNearestPoint(ADistFunc: TPointDistFunc;
|
||||
const APoint: TPoint; out AIndex: Integer; out AImg: TPoint; out
|
||||
AValue: TDoublePoint): Boolean;
|
||||
function TConstantLine.GetNearestPoint(
|
||||
const AParams: TNearestPointParams;
|
||||
out AResults: TNearestPointResults): Boolean;
|
||||
begin
|
||||
Unused(ADistFunc);
|
||||
Result := true;
|
||||
AIndex := -1;
|
||||
AImg := APoint;
|
||||
AResults.FIndex := -1;
|
||||
AResults.FImg := AParams.FPoint;
|
||||
// Return the actual nearest point of the line.
|
||||
if LineStyle = lsVertical then begin
|
||||
AValue.Y := FChart.YImageToGraph(APoint.Y);
|
||||
AImg.X := FChart.XGraphToImage(AxisToGraphX(Position));
|
||||
AResults.FValue.Y := FChart.YImageToGraph(AParams.FPoint.Y);
|
||||
AResults.FImg.X := FChart.XGraphToImage(AxisToGraphX(Position));
|
||||
end
|
||||
else begin
|
||||
AValue.X := FChart.XImageToGraph(APoint.X);
|
||||
AImg.Y := FChart.YGraphToImage(AxisToGraphX(Position));
|
||||
AResults.FValue.X := FChart.XImageToGraph(AParams.FPoint.X);
|
||||
AResults.FImg.Y := FChart.YGraphToImage(AxisToGraphX(Position));
|
||||
end;
|
||||
SavePosToCoord(AValue);
|
||||
SavePosToCoord(AResults.FValue);
|
||||
end;
|
||||
|
||||
function TConstantLine.GetSeriesColor: TColor;
|
||||
|
||||
@ -1061,34 +1061,28 @@ const
|
||||
DIST_FUNCS: array [TReticuleMode] of TPointDistFunc = (
|
||||
nil, @PointDistX, @PointDistY, @PointDist);
|
||||
var
|
||||
cur, best: record
|
||||
pointIndex: Integer;
|
||||
retPos: TPoint;
|
||||
value: TDoublePoint;
|
||||
end;
|
||||
cur, best: TNearestPointResults;
|
||||
p: TNearestPointParams;
|
||||
d, minDist: Double;
|
||||
df: TPointDistFunc;
|
||||
s, bestS: TCustomChartSeries;
|
||||
begin
|
||||
if FChart.ReticuleMode = rmNone then exit;
|
||||
minDist := SafeInfinity;
|
||||
df := DIST_FUNCS[FChart.ReticuleMode];
|
||||
p.FDistFunc := DIST_FUNCS[FChart.ReticuleMode];
|
||||
p.FPoint := APoint;
|
||||
for s in CustomSeries(FChart) do
|
||||
if
|
||||
s.GetNearestPoint(df, APoint, cur.pointIndex, cur.retPos, cur.value) and
|
||||
PtInRect(FChart.ClipRect, cur.retPos)
|
||||
then begin
|
||||
d := df(APoint, cur.retPos);
|
||||
if d < minDist then begin
|
||||
bestS := s;
|
||||
best := cur;
|
||||
minDist := d;
|
||||
end;
|
||||
if s.GetNearestPoint(p, cur) and PtInRect(FChart.ClipRect, cur.FImg) then begin
|
||||
d := p.FDistFunc(APoint, cur.FImg);
|
||||
if d < minDist then begin
|
||||
bestS := s;
|
||||
best := cur;
|
||||
minDist := d;
|
||||
end;
|
||||
end;
|
||||
if not IsInfinite(minDist) and (best.retPos <> FChart.ReticulePos) then begin
|
||||
FChart.ReticulePos := best.retPos;
|
||||
if not IsInfinite(minDist) and (best.FImg <> FChart.ReticulePos) then begin
|
||||
FChart.ReticulePos := best.FImg;
|
||||
if Assigned(FChart.OnDrawReticule) then
|
||||
FChart.OnDrawReticule(FChart, bestS.Index, best.pointIndex, best.value);
|
||||
FChart.OnDrawReticule(FChart, bestS.Index, best.FIndex, best.FValue);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1285,26 +1279,28 @@ end;
|
||||
|
||||
procedure TDataPointTool.FindNearestPoint(APoint: TPoint);
|
||||
var
|
||||
d, bestd, idx: Integer;
|
||||
d, bestd: Integer;
|
||||
s, bests: TCustomChartSeries;
|
||||
nearImg: TPoint;
|
||||
nearGraph: TDoublePoint;
|
||||
p: TNearestPointParams;
|
||||
cur, best: TNearestPointResults;
|
||||
begin
|
||||
bestd := MaxInt;
|
||||
bests := nil;
|
||||
p.FDistFunc := @PointDist;
|
||||
p.FPoint := APoint;
|
||||
for s in CustomSeries(FChart, ParseAffectedSeries) do begin
|
||||
if not s.GetNearestPoint(@PointDist, APoint, idx, nearImg, nearGraph) then
|
||||
continue;
|
||||
d := PointDist(APoint, nearImg);
|
||||
if not s.GetNearestPoint(p, cur) then continue;
|
||||
d := PointDist(APoint, cur.FImg);
|
||||
if d < bestd then begin
|
||||
bestd := d;
|
||||
bests := s;
|
||||
FPointIndex := idx;
|
||||
FNearestGraphPoint := nearGraph;
|
||||
best := cur;
|
||||
end;
|
||||
end;
|
||||
if (bests = nil) or (bestd > Sqr(GrabRadius)) then exit;
|
||||
FSeries := bests;
|
||||
FPointIndex := best.FIndex;
|
||||
FNearestGraphPoint := FChart.ImageToGraph(best.FImg);
|
||||
end;
|
||||
|
||||
function TDataPointTool.ParseAffectedSeries: TBooleanDynArray;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user