Getting pixel values from axis label values

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Getting pixel values from axis label values

Post by dpatch » Thu Aug 28, 2008 10:14 pm

I am trying to save the coordinates of a polygon that I marked on an image
displayed on a TColorGrid so that I can redraw the polygon at a later time.
My users save the polygon vertex values, and at a later date, draw a new image
using a different target and want to redraw the saved polygon.

Below is some example code that I use...


//
// This is the way I put data into the TColorGridSeries. My image data is
// stored in a 2D array of doubles called DblImageData. Note that IrrGrid is
// NOT defined because this code is still VERY slow.
//
for i := 0 to High(DblImageData) do
for j := 0 to High(DblImageData[0]) do
begin
{$ifndef IrrGrid}
// NOTE:
// We are adding 1 to the "X" and "Z" parameters as a work around for a bug
// steema has in their code that is suppose to be fixed in the next release.
// Setting IrregularGrid := True cause images to update REALLY slowly!
(Chart1.Series[SIndex] as TColorGridSeries).AddXYZ(i+1, DblImageData[i,j], j+1);
{$else}
// The axis here is much nicer, but redrawing the image is very slow when
// resizing.
(Chart1.Series[SIndex] as TColorGridSeries).AddXYZ(xScaleOff+i*xScaleMul,
DblImageData[i,j], zScaleOff+j*zScaleMul);
{$endif}
end;

//
// This is the way I fill in the Axis labels when IrregulatGrid is set to false
// which it is in my application.
//
{$ifndef IrrGrid}
// Fill in labels for the X axis.
for i := 0 to High(DblImageData) do
begin
x := i * xScaleMul + xScaleOff;
if (i mod (Length(DblImageData) Div 10) = 0) then
Chart1.Axes.Bottom.Items.add(i,Format('%-.2f',[x]));
end;

// Fill in labels for the Y axis.
for j := 0 to High(DblImageData[0]) do
begin
x := j * zScaleMul + zScaleOff;
if (j mod (Length(DblImageData) Div 10) = 0) then
Chart1.Axes.Left.Items.add(j,Format('%-.2f',[x]));
end;
{$Endif}


//
// I then draw a polygon on the image by getting mouse clicks and saving the
// axis values.
//
// So in procedure TPlotForm.Chart1MouseDown, I get the axis values of points
// clicked on the screen to draw a polygon. I save these points so that later I
// can redraw the polygon on another image with a different zoom and different
// screen size.
//
// NOTE: This is only a code snippet, it is not complete. Unessary application
// specific code and initialization was removed to simplify this example.
//
procedure TPlotForm.Chart1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
fIER_Array[High(fIER_Array)].X := X;
fIER_Array[High(fIER_Array)].Y := Y;

// Add the first vertex to the end of the list so we can close the polygon
// when we draw it
SetLength(fIER_Array, Length(fIER_Array)+1);
fIER_Array[High(fIER_Array)].X := fIER_Array[0].X;
fIER_Array[High(fIER_Array)].Y := fIER_Array[0].Y;

// Save polygon if there is more than 2 points in it.
if Length(fIER_Array) > 2 then
begin
// Draw the polygon.
Chart1.Canvas.Pen.Width := 1;
Chart1.Canvas.Polyline(fIER_Array);

// Save the current polygon in the IER shape list.
SetLength(fIERRecList, Length(fIERRecList)+1);
j := High(fIERRecList);
i := Length(fIER_Array);

// Pixel locations of each vertex
SetLength(fIERRecList[j].Point_List, i);
SetLength(fIERRecList[j].X_Values, i); // X axis values
SetLength(fIERRecList[j].Y_Values, i); // Y axis values

for i := 0 to High(fIER_Array) do
begin
// Save the X and Y pixel positions or the vertex points. This is
// really useless because the images sizez will be different!!
fIERRecList[j].Point_List := fIER_Array;

// Get the index of the point clicked.
k := Chart1.Series[0].Clicked(fIER_Array.X,fIER_Array.Y);

// Save the value of the axis label of the point clicked.
fIERRecList[j].X_Values := (k div (Chart1.Series[0] as TColorGridSeries).NumZValues) *
xScaleMul + xScaleOff;
fIERRecList[j].Y_Values := (k mod (Chart1.Series[0] as TColorGridSeries).NumZValues) *
zScaleMul + zScaleOff ;
end;
end;
end;



Now that I have the axis label values of the points in the polygon, how can I
go backwards to the pixel locations on a new image made sometime inthe future?

For example, if I collect data on a different target and display the image, I
want to redraw the polygon on the new target at the same x/y positions.

How do I get the pixel locations from the fIERRecList[j].X_Value and
fIERRecList[j].Y_Value arrays that I saved earlier?

Is there a better way to do this with Irregular grid set to False?

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Fri Aug 29, 2008 8:03 am

Hi dpatch,
How do I get the pixel locations from the fIERRecList[j].X_Value and
fIERRecList[j].Y_Value arrays that I saved earlier?
You can use CalcPosValue method for that:

Code: Select all

  XPos:=Chart1.Axes.Bottom.CalcPosValue(fIERRecList[j].X_Value);
  YPos:=Chart1.Axes.Left.CalcPosValue(fIERRecList[j].Y_Value);
Is there a better way to do this with Irregular grid set to False?
Not that I can think of. It is recommended to use IrregularGrid=false whenever possible as it makes series much more eficient.
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Post by dpatch » Fri Aug 29, 2008 2:25 pm

I saw the CalcPosValue method however, it takes an integer as input and my arrays are floating point. Is there an overloaded version that I did not see? I really need to be able to do this. Thanks...

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Fri Aug 29, 2008 2:37 pm

Hi dpatch,

No, CalcPosValue takes a double value for me and returns an integer. In a similar way, you can use CalcXPosValue and CalcYPosValue methods:
XPos:=Chart1.Axes.Bottom.CalcXPosValue(fIERRecList[j].X_Value);
YPos:=Chart1.Axes.Left.CalcYPosValue(fIERRecList[j].Y_Value);
Hope this helps!
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Post by dpatch » Fri Aug 29, 2008 8:22 pm

Yes, I see that you are correct. I was looking at the series1.CalcPosValue example in your help file.

When I call the example code you supplied, I did not get the right answer. I wonder if I did not save the axis value in the array X_Value correctly. Could you look at the end of the example code where I calculated this value and tell me if it is wrong?

X and Y are gotten in the OnMouseDown event.

// Get the index of the point clicked.
k := Chart1.Series[0].Clicked(X, Y);

// Save the value of the axis label of the point clicked.
fIERRecList[j].X_Values := (k div (Chart1.Series[0] as TColorGridSeries).NumZValues) * xScaleMul + xScaleOff;
fIERRecList[j].Y_Values := (k mod (Chart1.Series[0] as TColorGridSeries).NumZValues) * zScaleMul + zScaleOff ;

Thank you.

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Mon Sep 01, 2008 8:36 am

Hi dpatch,

You could try something easier:

Code: Select all

  fIERRecList[j].X_Values[i] := Chart1[0].XValue[k];
  fIERRecList[j].Y_Values[i] := Chart1[0].YValue[k];
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Post by dpatch » Mon Sep 01, 2008 3:32 pm

There are 2 problems with the solution that you recommend.

The first is that your solution returns the "integer" index of the X/Y pixel locations on the original axis when the Mouse Down event was generated. This index will not longer be valid on the next image that the uses generages...especially if it is at a different zoom. I also do not believe that calculating the axis value works with this index.

Secondly, I am not trying to get the index of the chart, I am trying to get the floating point value that I put into the axis label for that index. If you look carefully at my code segment below, you will see that I have a for loop that generates a floating point axis label value starting at an offset and multiplying by a scaling factor.

Is there a way to get directly to the floating point value of the axis from the X/Y coordinates in the Mouse Down event? Also, I need to get back from the floating point to the X/Y coordinate (or the pixel location) to be able to redraw the polygon an o different plot.

If this explanation is not clear, please make me explain myself better. I really need to be able to do this. I am afraid that this is not working because I am using IregularGrid := False.

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Tue Sep 02, 2008 8:15 am

Hi dpatch,

Thanks for the information.
Is there a way to get directly to the floating point value of the axis from the X/Y coordinates in the Mouse Down event?
Yes, in that case you can use CalcPosPoint method:

Code: Select all

  XVal:=Chart1.Axes.Bottom.CalcPosPoint(X);
  YVal:=Chart1.Axes.Left.CalcPosPoint(Y);
Also, I need to get back from the floating point to the X/Y coordinate (or the pixel location) to be able to redraw the polygon an o different plot.
For the inverse operation you can use this:

Code: Select all

  X:=Chart1.Axes.Bottom.CalcXPosValue(XVal);
  Y:=Chart1.Axes.Left.CalcYPosValue(YVal);
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Post by dpatch » Tue Sep 02, 2008 5:15 pm

Initially I tried this and it did not work. However, It was a problem on my side.

This works GREAT! Thank you very much!

dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Post by dpatch » Wed Sep 10, 2008 1:35 pm

OK, maybe I replied too fast...

The methods CalcPosPoint and CalcXPosValue do seem to work in that they allow me to redraw polygons in absoultuely the correct positions on different images. However, if you look at the axis positions values CalcPosPoint returns, it does not match the value on the x or y axis. Meaning, I have an axis scale that goes from -4.00 to +4.00 and CalcXPoint returns a number like 48.35475.

It's good that I can redraw the polygons, but I can't display the vertex values because they still are not correct.

Any thoughts on what I might be doing wrong?

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Wed Sep 10, 2008 1:43 pm

Hi dpatch,

Could you please send us a simple example project we can run "as-is" to reproduce the problem here?

You can either post your files at news://www.steema.net/steema.public.attachments newsgroup or at our upload page.

Thanks in advance.
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Post by dpatch » Wed Sep 10, 2008 2:00 pm

Yes, I will try to, but it is quite a lot of code...

It seems that the disconnect is between the values I load into the axis using:
Chart1.Series[SIndex].AddXYZ(i+1, DblImageData[i,j], j+1)

and the values I load into the x axis labels using:
Chart1.Axes.Bottom.Items.add(i,Format('%-.2f',[x]))

The code solution you gave me works, but it is calculating positions based on the values in chart.XValues array, not the values in the Chart.Axes label.

Is there a way to tie back to the values displayed onthe label? If so, I will put together some sample code and get it to you...

Thanks

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Post by Narcís » Wed Sep 10, 2008 2:20 pm

Hi dpatch,

I might be not understanding what you are trying to do. That's why a little code example would help.

Anyway, you could try using series' XScreenToValue and YScreenToValue which gives an axis value from a screen coordinate.
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Post by dpatch » Wed Sep 10, 2008 6:30 pm

OK, I sent a zip file with sample code to your upload site called "Image Test.zip".

I build this with Delphi 2006.

Let me know if you have any questions...

Thanks!

dpatch
Newbie
Newbie
Posts: 53
Joined: Mon Jul 02, 2007 12:00 am

Post by dpatch » Fri Sep 12, 2008 1:12 pm

Sorry to be a bother, I know you are busy. But did you receive the example code that I posted for you? Can you rebuild it and is it self explanitory enough?

Thanks

Post Reply