Page 1 of 1

Display text in OpenGL mode perpendicular to viewing axis

Posted: Tue Mar 09, 2010 1:37 pm
by 10547842
Hi,

in OpenGL mode all shown text rotates with the graphics/axes which makes it unreadable most of the time
(Please see: OpenGLModeText.png).
In normal 3D mode the text is always displayed perpendicular to the viewing axis.
(Please see: Normal3DModeText.png).
This is the preferred solution because in this way the text is readable in most cases.
How can I achieve the same result in OpenGL mode?

Thanks and best regards

Re: Display text in OpenGL mode perpendicular to viewing axis

Posted: Thu Mar 11, 2010 9:20 am
by yeray
Hi xray,

I'm afraid that OpenGL rotates the labels with the chart and I can't think on a way to workaround this right now.
What you could try is with GDIPlus where the labels don't seem to be rotated.

Code: Select all

         Chart1.Canvas:=TGDIPlusCanvas.Create;
         (Chart1.Canvas as TGDIPlusCanvas).AntiAlias:=True;

Re: Display text in OpenGL mode perpendicular to viewing axis

Posted: Thu Feb 17, 2011 10:47 pm
by 16556545
Hmmmm. Well, it should be simple enough to draw the text labels myself using the onAfterDraw event.

1) If I draw to a OpenGL canvas using onAfterDraw, wil my text still appear to be rotated?

2) I need to know WHERE to draw the text. How do I retrieve the x-y coordinates (in Canvas coordinates, NOT in chart coordinates) of each series point?

Still can't make both points AND text look good

Posted: Fri Feb 18, 2011 12:31 am
by 16556545
BACKGROUND: SPIN PLOTS

I'm trying to create a "spin" chart using TChart. A spin chart lets an analyst view a 3D scatter plot and spin it around by pitch, yaw and roll. Here is an animated GIF that is a good illustration:
macspin example.gif
macspin example.gif (140.35 KiB) Viewed 8393 times
With a modest number of points (up to 20 or 30, say), it would be desirable to be able to label each point. And that's where the challenge starts with TChart!!

NORMAL TCHART TOOLS

If I use normal TChart tools, plotted points look flat when we rotate 90 degrees. If we use OpenGL, text labels aren't drawn facing the viewer when we rotate, and vanish entirely once we rotate more than 90 degrees.

WHAT IF DRAW THE TEXT OURSELVES?

Here are some results using onAfterDraw to draw onto a chart that showing at an oblique angle:

Using a conventional chart:
-- TextOut(x, y, 'Hello') draws the text at a fixed x-y position on the chart. The text does not move as the chart is rotated.
-- TextOut3D(x, y, z, 'Hello') draws the text treating the x-y-z as chart coordinates, not canvas coordinates, so the text moves as the chart is rotated.
-- In both cases, the text is drawn facing the viewer (yea!)

Using an OpenGL chart created with TTeeOpenGL:
-- TextOut and TextOut3D appear to do exactly the same thing: the coordinates are treated as chart coords rather than canvas coords, so they move as the chart is rotated.
-- In both cases, the chart is drawn facing the original "outward" direction (towards positive-z). The text turns into a straight line when viewed at 90 degrees, and vanishes if we rotate any further.
-- I haven't found a way to draw text on an OpenGL chart that does NOT screw up the text when a chart is rotated.

CONCLUSIONS SO FAR

-- Given that we want 360 degree rotation with text labels, it seems using OpenGL and TTeeOpenGL is gorgeous, but worthless
-- In conventional charts, the only available point styles that can have depth (so they don't turn into lines at 90 degrees) are rectangle and triangle, NOT circles/spheres. So we can't draw a set of points without conveying a sense of the original axes (which is meaningless in most "spin" type applications.
-- The worst problem in conventional charts is that the z-ordering of drawn objects can get screwed up.
-- Solution? None yet, but I'm hopeful!

Given the huge breadth of styles and options in TChart, it's surprising that "spin" charts aren't a stock option.

Re: Display text in OpenGL mode perpendicular to viewing axis

Posted: Tue Feb 22, 2011 12:23 pm
by yeray
Hi Kevin,

In GDI and GDIPlus, it works fine with the following code:

Code: Select all

uses Series, TeePoin3;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var i: Integer;
    tmpX, tmpY, tmpZ: Integer;
    P               : TPoint;
begin
  for i:=0 to Chart1[0].Count-1 do
  begin
    tmpX:=Chart1[0].CalcXPos(i);
    tmpY:=Chart1[0].CalcYPos(i);
    tmpZ:=(Chart1[0] as TPoint3DSeries).CalcZPos(i);

    P:=Chart1.Canvas.Calculate3DPosition(tmpX, tmpY, tmpZ);

    Chart1.Canvas.TextOut(P.X+2,P.Y+2,FloatToStr(Chart1[0].YValue[i]));
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.Aspect.Orthogonal:=false;
  Chart1.Aspect.Zoom:=90;
  Chart1.Aspect.Rotation:=310;
  Chart1.Legend.Visible:=false;

  with Chart1.AddSeries(TPoint3DSeries) as TPoint3DSeries do
  begin
    Pointer.Style:=psCircle;
    LinePen.Visible:=False;
    FillSampleValues(10);
  end;

  Chart1.Draw;
end;
However, with OpenGL, this doesn't work perfect. I've added to the wish list the possibility to calculate the 3D positions of the points (TV52015408).
The following approach doesn't work fine with the elevation. It seems that the Calculate3DPositions method doesn't work as it should right now.

Code: Select all

uses TeeOpenGL, Series, TeeTools;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var i: Integer;
    tmpX, tmpY: Integer;
begin

  for i:=0 to Chart1[0].Count-1 do
  with Chart1.Tools[i] as TAnnotationTool do
  begin
    tmpX:=Round(Chart1[0].CalcXPos(i));
    tmpY:=Round(Chart1[0].CalcYPos(i));

    Chart1.Canvas.Calculate2DPosition(tmpX, tmpY, Chart1[0].MiddleZ);
    Left:=tmpX;
    Top:=Chart1.ClientRect.Top - tmpY;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  with TTeeOpenGL.Create(self) do
  begin
    TeePanel:=Chart1;
    Active:=true;
  end;

  Chart1.Aspect.Orthogonal:=false;
  Chart1.Aspect.Zoom:=50;
  Chart1.Aspect.Rotation:=310;
  Chart1.Legend.Visible:=false;

  with Chart1.AddSeries(TPointSeries)  as TPointSeries do
  begin
    Pointer.Style:=psCircle;
    FillSampleValues(10);
  end;

  for i:=0 to Chart1[0].Count-1 do
  with Chart1.Tools.Add(TAnnotationTool) as TAnnotationTool do
  begin
    Text:=FloatToStr(Chart1[0].YValue[i]);
    Shape.Transparent:=true;
  end;

  Chart1.Draw;
end;