TAChart: Use records to pass parameters to GetNearestPoint function

git-svn-id: trunk@32072 -
This commit is contained in:
ask 2011-08-28 04:40:05 +00:00
parent d0faffd601
commit cc324e9e04
4 changed files with 73 additions and 72 deletions

View File

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

View File

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

View File

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

View File

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