Announcement

Collapse
No announcement yet.

drawing text at an angle on a graphic window

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    drawing text at an angle on a graphic window

    This function from the forums looked promising, but does not draw its text where you would expect! Or possibly I should have stopped coding a couple of hours (or maybe decades) ago!

    Questions - what is wrong with this code? Is there a better way to do this?

    Code:
    #compile exe
    #dim all
    #include "win32api.inc"
    '---------------------------------------------
    ' Borje Hagsten, Dean Schrage et al
    sub drawrotatedtext( byval hdc                        as long     , _
                         s_textlabel                      as string   , _
                         s_fontname                       as string   , _
                         byval pointsize                  as long     , _
                         byval q_rotationangle            as double   , _
                         byval x                          as long     , _
                         byval y                          as long         )
    
       '  derives from http://www.powerbasic.com/support/pb...ad.php?t=10519
    
       dim lf         as logfont
       dim fnt        as long
       dim fntold     as long
       dim hfnt_old   as long
    
       lf.lfcharset         = %default_charset
       lf.lfclipprecision   = %clip_default_precis
       lf.lfescapement      = 10 * q_rotationangle
       lf.lforientation     = lf.lfescapement
       lf.lfheight          = - muldiv(pointsize, getdevicecaps(hdc&, %logpixelsy), 72)
       lf.lfweight          = 400    '  normal is 400 bold is 700
       lf.lfitalic          = 0
       lf.lfoutprecision    = %out_tt_only_precis
       lf.lfpitchandfamily  = %variable_pitch
       lf.lfquality         = %proof_quality
       lf.lfunderline       = 0
       lf.lfstrikeout       = 0
       lf.lffacename        = s_fontname
    
       fnt&     = createfontindirect(lf)
       fntold&  = selectobject(hdc&,fnt&)
    
       textout hdc&, x, y, byval strptr(s_textlabel), len(s_textlabel)
       hfnt_old = selectobject(hdc&, fntold&)
    
       deleteobject fnt&
    
    end sub
    '------------------------------------------
    function pbmain () as long
        local hDC, hGR as dword
        local d as double
        
        graphic window "TEST", 300, 300, 300, 100 to hGR
        graphic attach hGR, 0
        graphic get dc to hDC
        d = 30
        drawrotatedtext( hdc, "TEST", "ARIAL", 10, d, 100, 100)
        drawrotatedtext( hdc, "XXXX", "ARIAL", 10, d, 50, 50)
        drawrotatedtext( hdc, "ZZZZ", "ARIAL", 10, d, 150, 100)
        graphic redraw
        graphic waitkey$
    end function

    #2
    Hi Chris,

    Change:
    Code:
    textout hdc&, x, y, byval strptr(s_textlabel), len(s_textlabel)
    To:
    Code:
    MoveToEx hdc&, x, y, BYVAL 0&
    textout hdc&, 0, 0, byval strptr(s_textlabel), len(s_textlabel)
    Probably not completely what you want, but should give you a start. It seems to be that the text alignment for the graphic window includes %TA_UPDATECP, which means that calls to TextOut ignore x and y.

    From the MSDN page for TextOut
    By default, the current position is not used or updated by this function. However, an application can call the SetTextAlign function with the fMode parameter set to TA_UPDATECP to permit the system to use and update the current position each time the application calls TextOut for a specified device context. When this flag is set, the system ignores the nXStart and nYStart parameters on subsequent TextOut calls.
    Regards,

    Pete.

    Comment


      #3
      Chris, Not sure who this is from but it works great for me on the graphic window. (probably from Borje).

      Code:
      FUNCTION MakeRotatedFont (BYVAL hDC AS DWORD, BYVAL FontName AS STRING, _
                                BYVAL PointSize AS LONG, BYVAL Angle AS LONG, _
                                BYVAL fBold AS LONG, BYVAL fItalic AS LONG, _
                                BYVAL fUnderline AS LONG, BYVAL fStrikeThru AS LONG) AS DWORD
      'FUNCTION MakeRotatedFont (BYVAL hDC AS DWORD, BYVAL FontName AS STRING, _
      '                          BYVAL PointSize AS single, BYVAL Angle AS LONG, _
      '                          BYVAL fBold AS LONG, BYVAL fItalic AS LONG, _
      '                          BYVAL fUnderline AS LONG, BYVAL fStrikeThru AS LONG) AS DWORD
      
      '--------------------------------------------------------------------
      ' Create a rotated font. Angle is 1/10 of degrees, so 900 = 90 degrees.
      ' Uses EnumCharSet enumeration to get correct character set.
      '--------------------------------------------------------------------
      
        LOCAL CharSet AS SINGLE 'LONG
      
        PointSize = 0 - (PointSize * GetDeviceCaps(hDC, %LOGPIXELSY)) \ 72
        EnumFontFamilies hDC, BYVAL STRPTR(FontName), CODEPTR(EnumCharSet), BYVAL VARPTR(CharSet)
        IF Strikeout& THEN fStrikethru=1 ELSE fStrikethru=0
      'if strikeout& then msgbox "strikout&="+str$(strikeout&)
        FUNCTION = CreateFont(PointSize, 0, _  'height, width (default=0)
                   Angle, Angle, _             'escapement(angle), orientation
                   fBold, _                    'weight (%FW_DONTCARE = 0, %FW_NORMAL = 400, %FW_BOLD = 700)
                   fItalic, _                  'Italic (1/0)
                   fUnderline, _               'Underline (1/0)
                   fStrikeThru, _              'StrikeThru (1/0)
                   CharSet, %OUT_TT_PRECIS, _
                   %CLIP_DEFAULT_PRECIS, %DEFAULT_QUALITY, _
                   %FF_DONTCARE , BYCOPY FontName)
      
      END FUNCTION
      '====================================================================
      FUNCTION EnumCharSet (elf AS ENUMLOGFONT, ntm AS NEWTEXTMETRIC, _
                            BYVAL FontType AS LONG, CharSet AS LONG) AS LONG
        CharSet = elf.elfLogFont.lfCharSet
      END FUNCTION
      'Petr
      Last edited by Fred Buffington; 22 Oct 2009, 09:51 PM.
      Client Writeup for the CPA

      buffs.proboards2.com

      Links Page

      Comment


        #4
        Maybe you are missing some new features of PBCC5 Graphic Window ?


        Code:
         
        #COMPILE EXE
        #CONSOLE OFF
        #DIM ALL
        
        FUNCTION PBMAIN () AS LONG
         LOCAL x1,x2,y1,y2,Pixw,PixH,hwin,fnt1,fnt2 AS LONG
         DESKTOP GET CLIENT TO PixW,PixH
         x1=0
         y1=0
         x2=PixW
         y2=PixH
         GRAPHIC WINDOW " ",x1,y1,x2,y2 TO hwin
         GRAPHIC ATTACH hwin,0,REDRAW
         GRAPHIC CLEAR %WHITE
         GRAPHIC SET LOC 0,0
         GRAPHIC COLOR %BLACK,%WHITE 
         FONT NEW "COURIER NEW",40,0,0,0,450 TO fnt1
         FONT NEW "COURIER NEW",20,1,0,0,225 TO fnt2
         GRAPHIC SET FONT fnt1
         GRAPHIC SET POS(100,500)
         GRAPHIC PRINT "WRITING AT AN ANGLE"
         GRAPHIC SET FONT fnt2
         GRAPHIC SET POS(100,700)
         GRAPHIC PRINT "WRITING AT AN ANGLE"
         GRAPHIC REDRAW
         GRAPHIC WAITKEY$
         GRAPHIC WINDOW END
        END FUNCTION

        Comment


          #5
          Manuel has chose a fixed font, but I'll go a bit further to show a TT font and show graphihly what you really nee to consider for precise positioning. DDT fonts are located by the upper left corner of the envelope. The envelope however includes "internal leading" that must be accommodated if you need more precision. I've only illustrated how to get the offsets to show the top of the ascended portion of the characters which also illustrates the offset within the text envelope where the characters of the text string can ascend to.

          The text to the left indicates first the general character envelops and then the enveliope for each printed string. Using some of the code here you could easily determine the offsets for the internal leading, then subtract them from the X,Y where you want the actual character to start so PB sees the point where the envelope's top left corner should be.

          Code:
          #COMPILER PBCC 5, PBWIN 9
          #CONSOLE OFF
          #COMPILE EXE
          #DIM ALL
          %USEMACROS = 1
          #INCLUDE ONCE "win32api.inc"
          MACRO DegreesToRadians(dpDegrees) = (dpDegrees * 0.0174532925199433##)
          
          FUNCTION PBMAIN () AS LONG
          
              LOCAL hGR,hDC      AS DWORD
              LOCAL hFont,result AS LONG
              LOCAL SinA,CosA   AS EXT
              LOCAL offx,offy   AS SINGLE
              LOCAL offxIL,offyIL   AS SINGLE
              LOCAL a,b,c       AS STRING
              DIM LW(0 TO 3,1 TO 2)  AS SINGLE
              LOCAL TM          AS OUTLINETEXTMETRIC
              'FONT NEW fontname$ [,points!, style&, charset&, pitch&, escapement&] TO fhndl
          
              SinA = SIN(DegreesToRadians(30))
              CosA = COS(DegreesToRadians(30))
          
              FONT NEW "ARIAL",10,0,0,0,300 TO hFont
          
              GRAPHIC WINDOW "TEST", 300, 300, 300, 200 TO hGR
              GRAPHIC ATTACH hGR, 0,REDRAW
              GRAPHIC GET DC TO hDC
              GRAPHIC SET FONT hFont
              'for TrueType fonts use the following
              result& = GetOutlineTextMetrics(hDC,SIZEOF(OUTLINETEXTMETRIC),TM)
          
              'get height mainly for offset use
              GRAPHIC CHR SIZE TO LW(0,1),LW(0,2)
              offx = SinA*LW(0,2)
              offy = CosA*LW(0,2)
              'fudge the internal leading line to allow for line width of 1
              offxIL = SinA*(TM.otmTextMetrics.tmInternalLeading -1)
              offyIL = CosA*(TM.otmTextMetrics.tmInternalLeading -1)
              '
              GRAPHIC SET POS (100,100)
              GRAPHIC TEXT SIZE "TEST" TO LW(1,1),LW(1,2)
              GRAPHIC PRINT "TEST"
              GRAPHIC SET POS (50,50)
              GRAPHIC TEXT SIZE "XXXX" TO LW(2,1),LW(2,2)
              GRAPHIC PRINT "XXXX"
              GRAPHIC SET POS (150,150)
              GRAPHIC TEXT SIZE "ZZZZ" TO LW(3,1),LW(3,2)
              GRAPHIC PRINT "ZZZZ"
              FONT END hFont
              '
              a$ = FORMAT$(LW(1,1))+","+ FORMAT$(LW(1,2))
              b$ = FORMAT$(LW(2,1))+","+ FORMAT$(LW(2,2))
              c$ = FORMAT$(LW(3,1))+","+ FORMAT$(LW(3,2))
              '
              FONT NEW "ARIAL",10,0,0,0,0  TO hFont
              GRAPHIC SET FONT hFont
          
              GRAPHIC LINE (100,100)-(100+(cosA*LW(1,1)),100-(sinA*LW(1,1)))
              GRAPHIC LINE (100+offxIL,100+offyIL)-((100+offxIL)+(cosA*LW(1,1)),(100+offyIL)-(sinA*LW(1,1)))
              GRAPHIC LINE (100+offx,100+offy)-((100+offx)+(cosA*LW(1,1)),(100+offy)-(sinA*LW(1,1)))
              GRAPHIC LINE (100,100)- (100+offx,100+offy)
              GRAPHIC LINE (100+(cosA*LW(1,1)),100-(sinA*LW(1,1)))-((100+offx)+(cosA*LW(1,1)),(100+offy)-(sinA*LW(1,1)))
              GRAPHIC SET POS(1,100)
              GRAPHIC PRINT a$
          
              GRAPHIC LINE (50,50)-(50+(cosA*LW(2,1)),50-(sinA*LW(2,1)))
              GRAPHIC LINE (50+offxIL,50+offyIL)-((50+offxIL)+(cosA*LW(1,1)),(50+offyIL)-(sinA*LW(1,1)))
              GRAPHIC LINE (50+offx,50+offy)-((50+offx)+(cosA*LW(2,1)),(50+offy)-(sinA*LW(2,1)))
              GRAPHIC LINE (50,50)- (50+offx,50+offy)
              GRAPHIC LINE (50+(cosA*LW(2,1)),50-(sinA*LW(2,1)))-((50+offx)+(cosA*LW(2,1)),(50+offy)-(sinA*LW(2,1)))
              GRAPHIC SET POS(1,50)
              GRAPHIC PRINT b$
          
              GRAPHIC LINE (150,150)-(150+(cosA*LW(3,1)),150-(sinA*LW(3,1)))
              GRAPHIC LINE (150+offxIL,150+offyIL)-((150+offxIL)+(cosA*LW(1,1)),(150+offyIL)-(sinA*LW(1,1)))
              GRAPHIC LINE (150+offx,150+offy)-((150+offx)+(cosA*LW(3,1)),(150+offy)-(sinA*LW(3,1)))
              GRAPHIC LINE (150,150)-(150+offx,150+offy)
              GRAPHIC LINE (150+(cosA*LW(3,1)),150-(sinA*LW(3,1))) -((150+offx)+(cosA*LW(3,1)),(150+offy)-(sinA*LW(3,1)))
              GRAPHIC SET POS(1,150)
              GRAPHIC PRINT c$
          
              GRAPHIC SET POS (1,1)
              GRAPHIC PRINT "LG,HT"
              GRAPHIC SET POS (1,20)
              GRAPHIC PRINT FORMAT$(LW(0,1))+","+ FORMAT$(LW(0,2))
          
          
              GRAPHIC REDRAW
              GRAPHIC WAITKEY$
              FONT END hFont
          END FUNCTION
          Rick Angell

          Comment


            #6
            Thanks Pete, Fred, Manuel, and Richard. What a great response!

            Pete, are you nocturnal by any chance?

            I think Manuel's solution comes closest to my preferred approach, which is to write the minimum of code.

            Comment


              #7
              It can be even simpler to convert your original post, Chris. My code was to show the nuance of the internal leading's affect on positioning.

              The addition of the FONT NEW/END,GRAPHIC SET FONT/XPRINT SET FONT to PB BASIC made it easier for most needs than coding one's own API direct calls. even in a function like Borje's. With them handling the DC is not even required by your code for text management purposes.

              However, there can be situations where you might not be satisfied with positioning the the text ,angled or not, by the overall text string envelope's upper left corner, without considering the offset(s) for the internal leading. In my post this really a small part of the code to derive. A significant portion of the code is only illustrating the rotated envelope and the offset of the internal leading. Actually the code could be reduced to a couple of macros, functions or function and a macro. The end result would be placing the text upper left corner of the leftmost character. This could be helpful for some kinds of graphic work I would imagine.
              Rick Angell

              Comment


                #8
                The code below illustrates how to use positioning with the internal leading compensated for. It does not accommodate rotations more than 0 to 90 though ... at present. The idea is to show how you can reduce some positioning tasks for this kind of "accuracy" in setting where the traxt will appear.

                Code:
                #COMPILER PBCC 5, PBWIN 9
                #CONSOLE OFF
                #COMPILE EXE
                #DIM ALL
                %USEMACROS = 1
                #INCLUDE ONCE "win32api.inc"
                '===============================================================================
                MACRO DegreesToRadians(dpDegrees) = (dpDegrees * 0.0174532925199433##)
                '===============================================================================
                MACRO GSP(x,y,ox,oy)
                    GRAPHIC SET POS (x-ox,y-ox)
                END MACRO
                '===============================================================================
                SUB GetOffsets(ox AS SINGLE,oy AS SINGLE,theta AS SINGLE,gDC AS DWORD)
                    LOCAL SinA,CosA   AS EXT
                    LOCAL TM          AS OUTLINETEXTMETRIC
                    LOCAL result      AS LONG
                    SinA = SIN(DegreesToRadians(theta))
                    CosA = COS(DegreesToRadians(theta))
                    result& = GetOutlineTextMetrics(gDC,SIZEOF(OUTLINETEXTMETRIC),TM)
                    ox = SinA*(TM.otmTextMetrics.tmInternalLeading)
                    oy = CosA*(TM.otmTextMetrics.tmInternalLeading)
                END SUB
                '===============================================================================
                FUNCTION PBMAIN () AS LONG
                
                    LOCAL hGR,hDC      AS DWORD
                    LOCAL hFont,result AS LONG
                    LOCAL offx,offy   AS SINGLE
                    
                    FONT NEW "ARIAL",10,0,0,0,300 TO hFont
                
                    GRAPHIC WINDOW "TEST", 300, 300, 300, 200 TO hGR
                    GRAPHIC ATTACH hGR, 0,REDRAW
                    GRAPHIC GET DC TO hDC
                    GRAPHIC SET FONT hFont
                    GetOffsets offx,offy,30,hDC
                    '
                    GSP(100,100,offx,offy)
                    GRAPHIC PRINT "TEST"
                    GSP(50,50,offx,offy)
                    GRAPHIC PRINT "XXXX"
                    GSP(150,150,offx,offy)
                    GRAPHIC PRINT "ZZZZ"
                    GRAPHIC REDRAW
                    '
                    GRAPHIC WAITKEY$
                    FONT END hFont
                END FUNCTION
                Rick Angell

                Comment


                  #9
                  Originally posted by Richard Angell View Post
                  The code below illustrates how to use positioning with the internal leading compensated for.
                  For my present purposes pixel accuracy is unimportant but when the situation arises I shall return here, and I shall not be the only one...

                  Nice piece of work Rick!

                  Comment


                    #10
                    Richard Angell's point

                    The code below demonstrate the effect of writing at an angle on the left alignment of the text, since the turning point is the upper left corner of the font's envelope (shown as colored background), as was pointed out by Richard Angell. Logically the biggest missalignment happens at 45° (~0.6 the size of the font)

                    Code:
                     
                    #COMPILE EXE
                    #CONSOLE OFF
                    #DIM ALL
                    
                    FUNCTION PBMAIN () AS LONG
                     LOCAL x1,x2,y1,y2,Pixw,PixH,hwin,fnt1,fnt2,fnt3,fnt4 AS LONG
                     DESKTOP GET CLIENT TO PixW,PixH
                     x1=0
                     y1=0
                     x2=PixW
                     y2=PixH
                     GRAPHIC WINDOW " ",x1,y1,x2,y2 TO hwin
                     GRAPHIC ATTACH hwin,0,REDRAW
                     GRAPHIC CLEAR %WHITE
                     GRAPHIC SET LOC 0,0
                     FONT NEW "COURIER NEW",50,0,0,0,450 TO fnt1
                     FONT NEW "COURIER NEW",40,0,0,0,450 TO fnt2
                     FONT NEW "COURIER NEW",30,0,0,0,450 TO fnt3
                     FONT NEW "COURIER NEW",20,0,0,0,450 TO fnt4
                     GRAPHIC COLOR %BLACK,%WHITE
                     GRAPHIC LINE(100,410)-(100,900),%RED
                     GRAPHIC COLOR %BLACK,RGB(240,255,255)
                     GRAPHIC SET FONT fnt1
                     GRAPHIC SET POS(100,510)
                     GRAPHIC PRINT "COURIER NEW 50"
                     GRAPHIC SET FONT fnt2
                     GRAPHIC SET POS(100,610)
                     GRAPHIC PRINT "COURIER NEW 40"
                     GRAPHIC SET FONT fnt3
                     GRAPHIC SET POS(100,710)
                     GRAPHIC PRINT "COURIER NEW 30"
                     GRAPHIC SET FONT fnt4
                     GRAPHIC SET POS(100,810)
                     GRAPHIC PRINT "COURIER NEW 20"
                     GRAPHIC REDRAW
                     GRAPHIC SET FONT fnt1
                     GRAPHIC SET POS(569,510)
                     GRAPHIC PRINT "COURIER NEW 50"   '31
                     GRAPHIC SET FONT fnt2
                     GRAPHIC SET POS(576,610)
                     GRAPHIC PRINT "COURIER NEW 40"   '24
                     GRAPHIC SET FONT fnt3
                     GRAPHIC SET POS(581,710)         '19
                     GRAPHIC PRINT "COURIER NEW 30"
                     GRAPHIC SET FONT fnt4
                     GRAPHIC SET POS(588,810)         '12
                     GRAPHIC PRINT "COURIER NEW 20"
                     GRAPHIC LINE(600,410)-(600,900),%RED
                     GRAPHIC REDRAW
                     GRAPHIC WAITKEY$
                     GRAPHIC WINDOW END
                    END FUNCTION

                    Comment


                      #11
                      Nice illustration Manuel!
                      Rick Angell

                      Comment

                      Working...
                      X
                      😀
                      🥰
                      🤢
                      😎
                      😡
                      👍
                      👎