Ellipse Arc Length II

Category: Drawing

Date: 02-16-2022

Return to Index


'Compilable Example:  (Jose Includes)
#Compiler PBWin 10
#Compile Exe
#Dim All
%Unicode = 1
#Include "Win32API.inc"
 
Enum Equates Singular
   IDC_Graphic = 500
   IDC_Statusbar
   IDC_HalfAngle
   IDC_HalfChord
   IDC_Michael
   IDC_ChordWalker
End Enum
 
Global hDlg As Dword, rc As Rect, Choice, a,b As Long, BisectAngle,PI,theta1,theta2 As Single
 
Function PBMain() As Long
   Dialog Default Font "Tahoma",10,0
   Dialog New Pixels, 0, "Bisect Ellipse Arc",800,300,650,300, %WS_OverlappedWindow To hDlg
   Control Add Graphic, hDlg, %IDC_Graphic,"Push", 100,0,650,300
   Control Add Option, hDlg, %IDC_HalfAngle,"Half-Angle",10,10,90,20
   Control Add Option, hDlg, %IDC_HalfChord,"Half-Chord",10,30,90,20
   Control Add Option, hDlg, %IDC_Michael,"Michael",10,50,90,20
   Control Add Option, hDlg, %IDC_ChordWalker,"Walker",10,70,90,20
   Graphic Attach hDlg, %IDC_Graphic, ReDraw
   Control Add Statusbar, hDlg, %IDC_StatusBar, "Bisect Ellipse Arc",0,0,0,0
   Dialog Show Modal hDlg Call DlgProc
End Function
 
CallBack Function DlgProc() As Long
   Select Case Cb.Msg
      Case %WM_InitDialog
         PI = 3.14159
         theta1 = 1.5 * PI  '4.712385
         theta2 = 2 * PI    '6.28318
         Choice = 1
         Control Set Option hDlg, %IDC_HalfAngle, %IDC_HalfAngle, %IDC_Michael
      Case %WM_Command
         If Cb.Ctl = %IDC_HalfAngle   And Cb.CtlMsg = %BN_Clicked Then Choice=1 : BisectTheAngle(Choice)
         If Cb.Ctl = %IDC_HalfChord   And Cb.CtlMsg = %BN_Clicked Then Choice=2 : BisectTheAngle(Choice)
         If Cb.Ctl = %IDC_Michael     And Cb.CtlMsg = %BN_Clicked Then Choice=3 : BisectTheAngle(Choice)
         If Cb.Ctl = %IDC_ChordWalker And Cb.CtlMsg = %BN_Clicked Then Choice=4 : BisectTheAngle(Choice)
      Case %WM_Size
         Local w,h As Long
         Dialog Get Client hDlg To w,h
         Control Set Size hDlg, %IDC_Graphic, w-100,h-25
         rc.nTop = 10
         rc.nLeft = 10
         rc.nBottom = h - 30
         rc.nRight = w - 110
         a = (rc.nRight   - rc.nLeft)/2
         b = (rc.nBottom - rc.nTop)/2
         BisectTheAngle(Choice)
   End Select
End Function
 
Sub BisectTheAngle(Approach As Long)
   Local rVert, rHorz, x0,y0,x,y,x1,x2,y1,y2,xc,yc,tn,R,RP As Single
   Graphic Clear
   Graphic Pie (RC.nLeft,RC.nTop)-(RC.nRight,RC.nBottom),0,1.5*PI, %Blue          'full ellipse
   Graphic Pie (RC.nLeft,RC.nTop)-(RC.nRight,RC.nBottom),1.5*PI,2.0*PI, %Red      'lower right quadrant
   Select Case Approach
      Case 1  'half-angle
         BisectAngle = (theta1 + theta2)/2
         GetXYOnEllipsePerimeter RC, BisectAngle, x1,y1, %True, %Red
         Statusbar Set Text hDlg, %IDC_StatusBar, 1,0, "Half-Angle method"
      Case 2  'half-chord
         x0 = (rc.nRight + rc.nLeft) / 2 : y0 = (rc.nTop + rc.nBottom) / 2
         GetXYOnEllipsePerimeter RC, Theta1, x1,y1, %True, %Red
         GetXYOnEllipsePerimeter RC, Theta2, x2,y2, %True, %Red
         Graphic Line (x1,y1)-(x2,y2), %Green                'chord
         Graphic Line (x0,y0)-((x1+x2)/2,(y1+y2)/2), %Green  'line from center to midpoint of chord
         BisectAngle = Atn(-1*(y-y0)/(x-x0))                 'calculate the angle to the middle of the chord
         If y >= y0 And x >= x0 Then  'quadrant1
            'no change
         ElseIf y >= y0 And x <= x0 Then  'quadrant2
             BisectAngle += PI/2
         ElseIf y <= y0 And x <= x0 Then  'quadrant3
             BisectAngle += PI
         ElseIf y <= y0 And x >= x0 Then  'quadrant4
             BisectAngle += 1.5*PI
         End If
         GetXYOnEllipsePerimeter RC, BisectAngle, x1,y1, %True, %Red
         Statusbar Set Text hDlg, %IDC_StatusBar, 1,0, "Half-Chord method"
      Case 3  'Michael foreshortening
 
      Case 4  'Chord Walker
         x0 = (rc.nRight + rc.nLeft) / 2 : y0 = (rc.nTop + rc.nBottom) / 2
         RP = ArcLength(RC, theta1, theta2, 50)/2         'full perimeter
         GetXYOnEllipsePerimeter RC, Theta1, x1,y1, %True, %Red
         GetXYOnEllipsePerimeter RC, Theta2, x1,y1, %True, %Red
         For BisectAngle = theta2 To theta1 Step -0.01
            GetXYOnEllipsePerimeter RC, BisectAngle, x1,y1, %True, %Red
            R = ArcLength(RC, BisectAngle,theta2, 50)
            If R >= RP Then  Graphic Line (x0,y0)-(x1,y1),%Blue : Exit For  'Draw to point on ellipse perimeter
         Next i
         Statusbar Set Text hDlg, %IDC_StatusBar, 1,0, "Walker method"
   End Select
   Graphic ReDraw
   Beep
End Sub
 
Sub GetXYOnEllipsePerimeter (RC As Rect, ByVal theta As Single, x1 As Single, y1 As Single, DrawLineToXY As Long, iColor As Long)
   Local rVert, rHorz, x0,y0,x,y,tn As Single
   theta+=0.001
   rVert = (rc.nBottom - rc.nTop) / 2
   rHorz = (rc.nRight - rc.nLeft) / 2
   x0    = (rc.nRight + rc.nLeft) / 2
   y0    = (rc.nTop + rc.nBottom) / 2
   tn = Tan(-theta)
   x = rVert * rHorz      / ((rVert*rVert + rHorz*rHorz*tn*tn)^0.5)
   y = rVert * rHorz * tn / ((rVert*rVert + rHorz*rHorz*tn*tn)^0.5)
   If theta >= PI/2 And theta <= 1.5*PI Then x = -1 * x : y = -1 * y
   x1 = x0 + x
   y1 = y0 + y
   If DrawLineToXY Then Graphic Line (x0,y0)-(x1,y1), iColor
End Sub 


created by gbSnippets
http://www.garybeene.com/sw/gbsnippets.htm