Any maths gurus who can help with geometry?!

For everything that's not in any way related to PureBasic. General chat etc...
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Any maths gurus who can help with geometry?!

Post by Olliv »

Name : ScalePoint()

Action : Deforms the plane on which is drawn a point, wether horizontally, wether vertically. There is no angle change. For example: all what is perpendicular stays perpendicular, etc...

Inputs :
xCenter.F ; yCenter.F Center point position (in pixels)
xScale.F Horizontal coefficient (no unit) (1. = no change)
yScale.F Vertical coefficient (no unit) (1. = no change)
xSource.F ; ySource.F Source point position (in pixels)
*xResult.FLOAT, *yResult.FLOAT Result point pointors

Output :
xResult.F, yResult.F Result point position

Example :
Define.F x, y
ScalePoint(0., 0., 3., 2., 10., 10., @x, @y)
Debug x
Debug y
; Will display near 30. and near 20.

Define.F x, y
ScalePoint(1., 1., 2., 1., 10., 10., @x, @y)
Debug x
Debug y
; Will display near 19. and near 10.

Note:
For x and y scale value :
1. = no change
2. = double the size
3. = triple the size
.5 = divise the size by 2.
Etc...

Code: Select all

Procedure ScalePoint(xCenter.F, yCenter.F, xScale.F, yScale.F, xSource.F, ySource.F, *xResult.FLOAT, *yResult.FLOAT)
  *xResult\F = (xSource - xCenter) * xScale + xCenter
  *yResult\F = (ySource - yCenter) * yScale + yCenter
EndProcedure
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Any maths gurus who can help with geometry?!

Post by Olliv »

Now, in order to give you a concrete representation of what you are able when you get these 3 functions, I publish this code below.

It's an exercice... :D

When you run this code, you can see an ellipse.
You can scale the plane moving the mouse and rotate the plane turning the mouse wheel.

With scaling and rotating, from this ellipse, try to obtain a circle on the screen.
If we forget the quality of the resulting picture, is it possible?

:mrgreen:

If, for you, it's possible to obtain a circle manually, we could see the following procedure named CircleEquation() ...

Code: Select all

Procedure DrawArc(xCenter.F, yCenter.F, RadiusX.F, RadiusY.F, xRotation.F, Color.I, StartArc.F = 0., EndArc.F = 2. * #PI)
  Protected.F AngleStep, Angle, xEllipse, yEllipse, xDraw, yDraw, xPlot, yPlot
  AngleStep = #PI / (2. * (RadiusX + RadiusY) )
  If EndArc < StartArc
    EndArc + (2. * #PI)
  EndIf
  Angle = StartArc
  Repeat
    xEllipse.F = Cos(Angle) * RadiusX ;;
    yEllipse.F = Sin(Angle) * RadiusY ;;
    xDraw.F = Cos(xRotation) * xEllipse - Sin(xRotation) * yEllipse ;;
    yDraw.F = - Sin(xRotation) * xEllipse - Cos(xRotation) * yEllipse ;;
    xPlot.F = xCenter + xDraw
    yPlot.F = yCenter + yDraw 
    Box(xPlot, yPlot, 1, 1, Color)
    Angle + AngleStep
  Until Angle > EndArc
EndProcedure

Procedure.I DrawingProcedure(X.I, Y.I, Width.I, Height.I, *DrawingCode.INTEGER)
  Protected I.I
  Select *DrawingCode
    Case 1
      Box(X, Y, Width, Height, RGBA(255, 255, 255, 255) )
      For I = 0 To Width - 1 Step 5
        Line(I, 0, 1, Width, RGBA(200, 200, 255, 255) )
        Line(0, I, Width, 1, RGBA(200, 200, 255, 255) )
      Next I
      For I = 0 To Width - 1 Step 25
        Line(I, 0, 1, Width, RGBA(0, 200, 255, 255) )
        Line(0, I, Width, 1, RGBA(0, 200, 255, 255) )
      Next I
      For I = 0 To Width - 1 Step 50
        Line(I, 0, 1, Width, RGBA(255, 0, 255, 255) )
        Line(0, I, Width, 1, RGBA(255, 0, 255, 255) )
      Next I
    Case 2
      For I = 0 To Width - 1 Step 25
        Line(I, 0, 1, Width, RGBA(0, 200, 255, 255) )
        Line(0, I, Width, 1, RGBA(0, 200, 255, 255) )
      Next I
      For I = 0 To Width - 1 Step 50
        Line(I, 0, 1, Width, RGBA(255, 0, 255, 255) )
        Line(0, I, Width, 1, RGBA(255, 0, 255, 255) )
      Next I
      DrawingMode(#PB_2DDrawing_Outlined | #PB_2DDrawing_AlphaBlend)
      For i = 0 To 3
        DrawArc(Width / 2., Height / 2., 20. + i, 200. + i, 3. * #PI / 4., RGBA(255, 0, 0, 255) )
      Next i
  EndSelect
EndProcedure

Procedure.I MakeImage(Width.I, Height.I, *DrawingCode)
  Protected Image.I
  Image = CreateImage(#PB_Any, Width, Height, 32)
  StartDrawing(ImageOutput(Image) )
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0, 0, Width, Height, RGBA(0, 0, 0, 0) )
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    DrawingProcedure(0, 0, Width, Height, *DrawingCode)
  StopDrawing()
  ProcedureReturn Image
EndProcedure

Procedure.I MakeSprite(Width.I, Height.I, Image.I)
  Protected Sprite.I
  Sprite = CreateSprite(#PB_Any, Width, Height, #PB_Sprite_Texture | #PB_Sprite_AlphaBlending)
  StartDrawing(SpriteOutput(Sprite) )
    DrawAlphaImage(ImageID(Image), 0, 0)
  StopDrawing()
  ProcedureReturn Sprite
EndProcedure

Procedure.I MakeSprite3D(Sprite.I)
  Protected Sprite3D.I
  Sprite3D = CreateSprite3D(#PB_Any, Sprite)
  Start3D()
    DisplaySprite3D(Sprite3D, 0, 0)
  Stop3D()
  ProcedureReturn Sprite3D
EndProcedure

Procedure InitDevices()
  InitSprite()
  InitSprite3D()
  InitKeyboard()
  InitMouse()
EndProcedure

Procedure InitScreen(*Width.INTEGER, *Height.INTEGER, *Depth.INTEGER)
  ExamineDesktops()
  *Width\I = DesktopWidth(0)
  *Height\I = DesktopHeight(0)
  *Depth\I = DesktopDepth(0)
  OpenScreen(*Width\I, *Height\I, *Depth\I, "")
EndProcedure

Structure XYInfo
  X.F
  Y.F
EndStructure

Structure SqInfo
  P.XYInfo[4]
EndStructure

Procedure RotatePoint(xCenter.F, yCenter.F, xSource.F, ySource.F, Beta.F, *xResult.FLOAT, *yResult.FLOAT)
    Protected.F xDelta1, yDelta1
    Protected.F xRef, yRef
    xDelta1 = xSource - xCenter
    yDelta1 = ySource - yCenter
    xRef = Cos(Beta)
    yRef = Sin(Beta)
    *xResult\F = xCenter + xRef * xDelta1 + yRef * yDelta1
    *yResult\F = yCenter - yRef * xDelta1 + xRef * yDelta1
EndProcedure

  InitDevices()
  Define DeskWidth.I
  Define DeskHeight.I
  Define DeskDepth.I
  InitScreen(@DeskWidth, @DeskHeight, @DeskDepth)
  Define Sprite3DSize.I = 1024
  Define Sprite3DRenderSize.I = 1024

  Define Image.I = MakeImage(Sprite3DSize, Sprite3DSize, 2)
  Define Sprite.I = MakeSprite(Sprite3DSize, Sprite3DSize, Image)
  Define Sprite3D.I = MakeSprite3D(Sprite)

  Define Image2.I = MakeImage(Sprite3DSize, Sprite3DSize, 1)
  Define Sprite2.I = MakeSprite(Sprite3DSize, Sprite3DSize, Image2)
  Define S3RefX.I = MakeSprite3D(Sprite2)

  Define S3X0.F = DeskWidth / 2.
  Define S3Y0.F = DeskHeight / 2.
  
  Define S3X1.F
  Define S3Y1.F
  Define S3X2.F
  Define S3Y2.F
  Define S3X3.F
  Define S3Y3.F
  Define S3X4.F
  Define S3Y4.F
  
  Define S4X1.F
  Define S4Y1.F
  Define S4X2.F
  Define S4Y2.F
  Define S4X3.F
  Define S4Y3.F
  Define S4X4.F
  Define S4Y4.F
  
  Define *S.SqInfo = @S3X1

  Define S3Rho.F = 512 * Sqr(2.)
  Define S3xRho.F = 1.
  Define S3yRho.F = 1.
  Define S3Teta.F = 0.
  Define Shift.F = 0.016
  Define Thick.F = 0.0015
  Define ScaleX.F
  Define ScaleY.F
  Define RhoX.F = 1.
  Define RhoY.F = 1.
  Define Angle.F
  ScaleX = 1.
  ScaleY = 1.
  Rho = Sqr(2.) * 512.
  Repeat
    Delay(16)
    ExamineKeyboard()
    ExamineMouse()
    S3TetaAcc.F + MouseWheel() / 2000.    
    S3Teta + S3TetaAcc
    If MouseButton(1)
      ScaleX + MouseDeltaX() / 100. 
      ScaleY - MouseDeltaY() / 100.
    Else
      RhoX + MouseDeltaX() / 100. 
      RhoY - MouseDeltaY() / 100.
    EndIf
    Teta.F = 0.
    For I = 0 To 3
      Angle = (3. * #PI / 4.) - I * (#PI / 2.)
      DrawX.F = Cos(Angle) * Rho * ScaleX
      DrawY.F = Sin(Angle) * Rho * ScaleY
      RotatePoint(0., 0., DrawX, DrawY, S3Teta, @DrawX, @DrawY)
      *S\P[I]\X = S3X0 + DrawX * RhoX
      *S\P[I]\Y = S3Y0 - DrawY * RhoY
    Next
    ClearScreen(RGB(0, 0, 0) )
    Start3D()
      Sprite3DQuality(#PB_Sprite3D_BilinearFiltering)
      DisplaySprite3D(S3RefX, 0, 0)
      DisplaySprite3D(Sprite3D, 0, 0)
      If used = 0
        used = 1
        CopyMemory(@S3X1, @S4X1, 32)
      EndIf
      TransformSprite3D(S3RefX, S4X1, S4Y1, S4X2, S4Y2, S4X3, S4Y3, S4X4, S4Y4)
      TransformSprite3D(Sprite3D, S3X1, S3Y1, S3X2, S3Y2, S3X3, S3Y3, S3X4, S3Y4)
    Stop3D()
    FlipBuffers()
  Until KeyboardPushed(#PB_Key_Escape)
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Any maths gurus who can help with geometry?!

Post by Olliv »

Name : CircleEquation()

Action : Solve the circle equation from two points positions and the radius length and give the two possible centers.

Inputs :
x1.F, y1.F = First point position
x2.F, y2.F = Second point position
R0.F = Radius length
*px0.FLOAT, *py0.FLOAT = First center position pointor
*pxE.FLOAT, *pyE.FLOAT = Second center position pointor

Output :
Result.I = Boolean
If =#True, there is one or two (more often) solutions.
If =#False, there is no real solution.
px0.F, py0.F = First center position
pxE.F, pyE.F = Second center position

Example :
Define.F px0, py0, pxE, pyE
CircleEquation(9., 8., 11., 10., 2., @px0, @py0, @pxE, @pyE)
Debug px0
Debug py0
Debug pxE
Debug pyE
; Will display near 9., near 10. for P0
; and near 11. near 8. for PE

Note:
I insist in the fact I got this algo thanks to the site of Michel Berteau. In this site, this whole page is dedicated to circle intersection equation. In the procedure below, you can see the three lines each starting by A=... B=... and C=... . It matchs exactly with the solution A=... B=... and C=... written in the math page. I insist because, we can stop on this apparently useless question of "WHY" such these calculation. The thing which breaks me, (if I forget the translation...) is the default of math symbol edition in this forum. But there is solutions for that. So, if anybody is intersted by this math demonstration question, I can publish it and explain step by step the math technic of this mathematician and suggest all you can do with this technic. For example, answer the question of sRod: how to get the 4 extrema points of an ellipse without the using of the slower algo that I and Idle published in this subject.

Code: Select all

Procedure.I CircleEquation(x1.F, y1.F, x2.F, y2.F, R0.F, *px0.FLOAT, *py0.FLOAT, *pxE.FLOAT, *pyE.FLOAT)
  Protected.I Result
  Protected.F x1P2, y1P2, x2P2, y2P2, xDelta, yDelta, Dir
  Protected.F N, A, B, C, Base, Root, x0, y0, xE, yE
  Protected.I FlipFlag
  If y1 = y2
    Swap x1, y1
    Swap x2, y2
    FlipFlag = 1
  EndIf
  xDelta = x1 - x2
  yDelta = y1 - y2
  Dir = xDelta / yDelta
  x1P2 = x1 * x1
  y1P2 = y1 * y1
  x2P2 = x2 * x2
  y2P2 = y2 * y2
  N = (x1P2 - x2P2 + y1P2 - y2P2) / (2. * yDelta)
  A = (Dir * Dir) + 1.
  B = 2. * ((y1 * Dir) - (N * Dir) - x1)
  C = x1P2 + y1P2 + (N + R0) * (N - R0) - (2. * Y1 * N)
  Delta = (B * B) - (4. * A * C)
  If Delta => 0.
    Base = - B / (2. * A)
    Root = Sqr(Delta) / (2. * A)
    x0 = Base - Root
    y0 = N - (x0 * Dir)
    xE = Base + Root
    yE = N - (xE * Dir)
    If FlipFlag
      Swap x0, y0
      Swap xE, yE
    EndIf
    *px0\F = x0
    *py0\F = y0
    *pxE\F = xE
    *pyE\F = yE
    Result = #True
  Else
    Result = #False
  EndIf
  ProcedureReturn Result
EndProcedure
User avatar
idle
Always Here
Always Here
Posts: 5884
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Any maths gurus who can help with geometry?!

Post by idle »

thanks Olliv, this is good information especially for those of us that are mathematically challenged. :D
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Any maths gurus who can help with geometry?!

Post by Olliv »

Ups! It will be difficult because my translation is bad I think... :D ... But it's possible!!

Normally, there is all the necessary above to understand that really we need to find the centers of two circles which are the base form of our arc.

Indeed, the first thing which helped me is the link Seymour Clufley published. This link pointed to SVG norm created by the W3C. I saw the picture in which there is really TWO equal ellipses when we draw an elliptic arc. So, I thank these two ellipses could be transformed to become two equal circles. The problem is WHERE IS (ARE) THE CENTER(S)?

We have the radii (x and y), the xRotation angle and the positions x;y of the two points. Radii and xRotation allows us to transform ellipses to circles.

Really, the start point and the end point of the arc are the two intersection points. We have their accurate position, and we have the radius of the two equal circles. This radius value depend of your convention, when you scaled the plane to transform the ellipses to circles. Final circle radius is wether equal to xRadius, wether equal to yRadius.


The real problem in math is exactly not to believe you are a guru!!! Just find all the datas before calculating. I am not a guru. If there is a man which is better than me, it's this mathematician. But I am sure, without knowing him, he thinks he is not himself a math guru. Because, the most beautiful rule in math it's just consider, whatever you know, it's never enough. And whatever you know again, wherever you go in calculation, you start with the fact that 1 + 2 = 3. You always start at a point which is simple. If it doesn't start simply, it's not maths!!

And what is simple here is these two circles we obtained after two simple transformations (1 rotation + 1 scale) I showed in the exercice above. Isn't it simple?

If yes, you could understand if two equal circles are always kissing themselves, like we have here and now, so, exactly like a little egg in the uterus of a woman and at the simple start of the life, two others equal circles are appearing.

Is this simple?!?
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Any maths gurus who can help with geometry?!

Post by Olliv »

Apparently and actually, it doesn't look like such simple as I think it... Let's draw a little bit...

Code: Select all

OpenWindow(0, 0, 0, 400, 300, "An egg in an uterus", $CF0001)
Repeat
  Delay(1)
  StartDrawing(WindowOutput(0) )
    DrawingMode(#PB_2DDrawing_Outlined | #PB_2DDrawing_Transparent)
    For I = -1 To 1 Step 2
      For J = -1 To 1 Step 2
        Gen = (((I + 1) / 2) ! ((J + 1) / 2) )
        Circle(200 + 32 * I, 150 + 32 * J, 64, RGB(Gen * 255 , 0, 255) )
        DrawText(16, 16 + 16 * Gen, "Generation " + Str(Gen + 1), RGB(Gen * 255, 0, 255) )
      Next J
    Next I
  StopDrawing()
Until WindowEvent() = 16
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Any maths gurus who can help with geometry?!

Post by Olliv »

I have a harmless question: do you think I am nutty? :D
Maybe a problem of translation?
Seymour Clufley
Addict
Addict
Posts: 1265
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Re: Any maths gurus who can help with geometry?!

Post by Seymour Clufley »

Hello Ollivier,

I have integrated your code into PureSVG, and the new version of the library will be posted in a few days.

Thank you very much for your work. I could never have written that code! You may find maths simple but... well, I'm always amazed by people who can do maths. (I'm a "language" guy.)

I do have one question about your code. Why does the CircleEquation procedure fail if the two points are too far apart?

Seymour.

PS. I don't think you're nutty. ;)
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Any maths gurus who can help with geometry?!

Post by Olliv »

Seymour wrote:I do have one question about your code. Why does the CircleEquation procedure fail if the two points are too far apart?
It's a clever question! :mrgreen:

When the 2 points are too far, it's a second problem in the first one. Let's consider a ball is perfectly spherical, in order to catch a ball, my two hands must have a distance maximum equal the radius of the ball. If they are too far, I can't simply catch the ball!!

In this draw, it's idem. Your question is clever...

1) because there is really solutions. But I didn't know which solution, do you want to apply. You said, we know xStart, yStart, xEnd and yEnd. The worry is I don't know if I can modify them. Basically, these are inputs data.

2) because I didn't ask it myself! :D There is two solution ways:
>> 2a) If the 2 points are too far, we can bring them near. But 3 sub-solutions are available:
>>>> 2a.1) The start point is changing
>>>> 2a.2) The end point is changing
>>>> 2a.3) The two points are changing

>> 2b) If the 2 points are too far, we can check if a rotation of the ellipse allow us to obtain a real solution. In this way, an other equation to get the rotation angle is necessary. This second equation can be without solution. In this way, (2a) is to be forseen. Conclusion: Ellipse rotation angle is changing

That's the reason math proc "failed" (it forcomes through the result) in the way the points are too far actually.

I can do an update, but you must specify which variable(s) can be modified:
[ ] Rotation angle
[ ] x,y start point
[ ] x,y end point

(The 3 ones can be checked)
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Any maths gurus who can help with geometry?!

Post by Olliv »

Code: Select all

;http://pagesperso-orange.fr/math.15873/index.htm
;http://pagesperso-orange.fr/math.15873/IntCercl.html

;http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
;http://www.w3.org/TR/SVG/images/paths/arcs02.png
;http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes

Procedure.F GetOrientation(xCenter.F, yCenter.F, xSource.F, ySource.F)
    Protected.F xDelta, yDelta
    Protected.F Rho, Alpha
    xDelta = xSource - xCenter
    yDelta = ySource - yCenter
    Rho = Sqr((xDelta * xDelta) + (yDelta * yDelta) )
    Alpha = ACos(xDelta / Rho)
    If yDelta > 0.
      Alpha = - Alpha
    EndIf
    ProcedureReturn Alpha
EndProcedure

Procedure RotatePoint(xCenter.F, yCenter.F, xSource.F, ySource.F, Beta.F, *xResult.FLOAT, *yResult.FLOAT)
    Protected.F xDelta1, yDelta1
    Protected.F xRef, yRef
    xDelta1 = xSource - xCenter
    yDelta1 = ySource - yCenter
    xRef = Cos(Beta)
    yRef = Sin(Beta)
    *xResult\F = xCenter + xRef * xDelta1 + yRef * yDelta1
    *yResult\F = yCenter - yRef * xDelta1 + xRef * yDelta1
EndProcedure

Procedure ScalePoint(xCenter.F, yCenter.F, xScale.F, yScale.F, xSource.F, ySource.F, *xResult.FLOAT, *yResult.FLOAT)
  *xResult\F = (xSource - xCenter) * xScale + xCenter
  *yResult\F = (ySource - yCenter) * yScale + yCenter
EndProcedure

Procedure.I _CircleEquation(x1.F, y1.F, x2.F, y2.F, R0.F, *px0.FLOAT, *py0.FLOAT, *pxE.FLOAT, *pyE.FLOAT)
  Protected.I Result
  Protected.F x1P2, y1P2, x2P2, y2P2, xDelta, yDelta, Dir
  Protected.F N, A, B, C, Base, Root, x0, y0, xE, yE
  Protected.I FlipFlag
  If y1 = y2
    Swap x1, y1
    Swap x2, y2
    FlipFlag = 1
  EndIf
  xDelta = x1 - x2
  yDelta = y1 - y2
  Dir = xDelta / yDelta
  x1P2 = x1 * x1
  y1P2 = y1 * y1
  x2P2 = x2 * x2
  y2P2 = y2 * y2
  N = (x1P2 - x2P2 + y1P2 - y2P2) / (2. * yDelta)
  A = (Dir * Dir) + 1.
  B = 2. * ((y1 * Dir) - (N * Dir) - x1)
  C = x1P2 + y1P2 + (N + R0) * (N - R0) - (2. * Y1 * N)
  Delta = (B * B) - (4. * A * C)
  If Delta => 0.
    Base = - B / (2. * A)
    Root = Sqr(Delta) / (2. * A)
    x0 = Base - Root
    y0 = N - (x0 * Dir)
    xE = Base + Root
    yE = N - (xE * Dir)
    If FlipFlag
      Swap x0, y0
      Swap xE, yE
    EndIf
    *px0\F = x0
    *py0\F = y0
    *pxE\F = xE
    *pyE\F = yE
    Result = #True
  Else
    Result = #False
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure.I CircleEquation(x1.F, y1.F, x2.F, y2.F, R0.F, *px0.FLOAT, *py0.FLOAT, *pxE.FLOAT, *pyE.FLOAT)
  Protected.F x1P2, y1P2, x2P2, y2P2, yDelta, Dir, N, B, C, Base, Root, DoubleA
  If y1 = y2
    Swap x1, y1
    Swap x2, y2
    FlipFlag = 1
  EndIf
  yDelta = y1 - y2
  If yDelta <> 0.
    Dir = (x1 - x2) / yDelta
    x1P2 = x1 * x1
    y1P2 = y1 * y1
    N = (x1P2 - (x2 * x2) + y1P2 - (y2 * y2) ) / (2. * yDelta)
    DoubleA = 2. * ((Dir * Dir) + 1.)
    B = 2. * ((y1 * Dir) - (N * Dir) - x1)
    C = x1P2 + y1P2 + (N + R0) * (N - R0) - (2. * Y1 * N)
    Delta = (B * B) - (2. * DoubleA * C)
    If Delta => 0.
      Base = - B / DoubleA
      Root = Sqr(Delta) / DoubleA
      *px0\F = Base - Root
      *py0\F = N - (*px0\F * Dir)
      *pxE\F = Base + Root
      *pyE\F = N - (*pxE\F * Dir)
      If FlipFlag
        Swap *px0\F, *py0\F
        Swap *pxE\F, *pyE\F
      EndIf
      ProcedureReturn #True
    EndIf
  EndIf
EndProcedure

Procedure.I GetArcChars(xStart.F, yStart.F, xEnd.F, yEnd.F, yRadius.F, xRadius.F, xRotation.F, LargeArcFlag.I, SweepFlag.I, *xResult1, *yResult1, *xResult2, *yResult2, *StartAngle, *EndAngle)
  Protected.I Result
  Protected.F xTemp, yTemp, xTmp, yTmp, xTmp0, yTmp0
  Protected.F StartArc, EndArc, xA, yA, xB, yB, A1, A2, A3
  RotatePoint(xStart, yStart, xEnd, yEnd, - xRotation, @xTemp, @yTemp)
  ScalePoint(xStart, yStart, 1.0, yRadius / xRadius, xTemp, yTemp, @xTemp, @yTemp)
  If CircleEquation(xStart, yStart, xTemp, yTemp, yRadius, @xTmp, @yTmp, @xTmp0, @yTmp0)
    StartArc = GetOrientation(xTmp, yTmp, xStart, yStart)
    EndArc = GetOrientation(xTmp, yTmp, xTemp, yTemp)
    ScalePoint(xStart, yStart, 1.0, xRadius / yRadius, xTmp, yTmp, @xTmp, @yTmp)
    ScalePoint(xStart, yStart, 1.0, xRadius / yRadius, xTmp0, yTmp0, @xTmp0, @yTmp0)
    RotatePoint(xStart, yStart, xTmp, yTmp, xRotation, @xA, @yA)
    RotatePoint(xStart, yStart, xTmp0, yTmp0, xRotation, @xB, @yB)
    A1.F = GetOrientation(xStart, yStart, xA, yA) + #PI
    A2.F = GetOrientation(xStart, yStart, xEnd, yEnd) + #PI
    A3.F = GetOrientation(xStart, yStart, xB, yB) + #PI
    If ((A1 > A2) And (A2 > A3) ) Or ((A1 < A2) And (A2 > A3) And (A1 < A3) ) Or ((A1 > A2) And (A2 < A3) And (A1 < A3) )
       Swap xA, xB
       Swap yA, yB
       Swap StartArc, EndArc
       StartArc + #PI
       EndArc + #PI
    EndIf
    If LargeArcFlag = #False
      Swap xA, xB
      Swap yA, yB
      Swap StartArc, EndArc
      StartArc + #PI
      EndArc + #PI
    EndIf
    If SweepFlag
      Swap xA, xB
      Swap yA, yB
      StartArc + #PI
      EndArc + #PI
    EndIf
    PokeF(*StartAngle, StartArc)
    PokeF(*EndAngle, EndArc)
    PokeF(*xResult1, xA)
    PokeF(*yResult1, yA)
    PokeF(*xResult2, xB)
    PokeF(*yResult2, yB)
    Result = #True
  Else
    Result = #False
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure DrawArc(xCenter.F, yCenter.F, RadiusX.F, RadiusY.F, xRotation.F, Color.I, StartArc.F = 0., EndArc.F = 2. * #PI)
  Protected.F AngleStep, Angle, xEllipse, yEllipse, xDraw, yDraw, xPlot, yPlot
  AngleStep = #PI / (2. * (RadiusX + RadiusY) )
  If EndArc < StartArc
    EndArc + (2. * #PI)
  EndIf
  Angle = StartArc
  Repeat
    xEllipse.F = Cos(Angle) * RadiusX ;;
    yEllipse.F = Sin(Angle) * RadiusY ;;
    xDraw.F = Cos(xRotation) * xEllipse - Sin(xRotation) * yEllipse ;;
    yDraw.F = - Sin(xRotation) * xEllipse - Cos(xRotation) * yEllipse ;;
    xPlot.F = xCenter + xDraw
    yPlot.F = yCenter + yDraw 
    Box(xPlot, yPlot, 1, 1, Color)
    Angle + AngleStep
  Until Angle > EndArc
EndProcedure

Procedure GimbalDot(xCenter.F, yCenter.F, RadiusX.F, RadiusY.F, xRotation.F, Angle.F, *xPlot.FLOAT, *yPlot.FLOAT)
  Protected.F xEllipse, yEllipse, xDraw, yDraw
  xEllipse = Cos(Angle) * RadiusX ;;
  yEllipse = Sin(Angle) * RadiusY ;;
  xDraw = Cos(xRotation) * xEllipse - Sin(xRotation) * yEllipse ;;
  yDraw = - Sin(xRotation) * xEllipse - Cos(xRotation) * yEllipse ;;
  *xPlot\F = xCenter + xDraw
  *yPlot\F = yCenter + yDraw 
EndProcedure

Procedure GetBoundArc(*Left.Float, *Top.Float, *Right.Float, *Bottom.Float, xCenter.F, yCenter.F, RadiusX.F, RadiusY.F, xRotation.F, StartArc.F = 0., EndArc.F = 2. * #PI)
  Protected.F AngleStep, Angle, xEllipse, yEllipse, xDraw, yDraw, xPlot, yPlot
  AngleStep = #PI / (2. * (RadiusX + RadiusY) )
  If EndArc < StartArc
    EndArc + (2. * #PI)
  EndIf
  Angle = StartArc
  *Left\F = 9999999.
  *Top\F = 9999999.
  *Right\F = -9999999.
  *Bottom\F = -9999999.
  Repeat
    xEllipse.F = Cos(Angle) * RadiusX ;;
    yEllipse.F = Sin(Angle) * RadiusY ;;
    xDraw.F = Cos(xRotation) * xEllipse - Sin(xRotation) * yEllipse ;;
    yDraw.F = - Sin(xRotation) * xEllipse - Cos(xRotation) * yEllipse ;;
    xPlot.F = xCenter + xDraw
    yPlot.F = yCenter + yDraw
    If xPlot < *Left\F
      *Left\F = xPlot
    EndIf
    If xPlot > *Right\F
      *Right\F = xPlot
    EndIf
    If yPlot < *Top\F
      *Top\F = yPlot
    EndIf
    If yPLot > *Bottom\F
      *Bottom\F = yPlot
    EndIf
    Angle + AngleStep
  Until Angle > EndArc
EndProcedure

  Define.F xA, yA, xB, yB, StartArc, EndArc
  Define.I LargeArcFlag, SweepFlag
  Define.F Left, Top, Right, Bottom
  
  Define.F ArcAngleEnd, ArcAngleStart
  ArcAngleStart = #PI / 2.
  ArcAngleEnd = 7. * #PI / 8.
  InitSprite()
  InitKeyboard()
  InitMouse()
  ExamineDesktops()
  dw = DesktopWidth(0)
  dh = DesktopHeight(0)
  dd = DesktopDepth(0)
  OpenScreen(dw, dh, dd, "")
  LoadFont(0, "VERDANA", 16)
  ArcX = dw / 2.
  ArcY = dh / 2.
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "0) Press the [Space] key when you read such a sentence...", #White)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
;    Delayed = Elapsed + 16
;    Repeat
;      Delay(1)
;      Elapsed = ElapsedMilliseconds()
;    Until Elapsed > Delayed
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "1) Let's imagine an arc...", #White)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "2) We know it's an ELLIPTIC arc...", #White)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(64, 0, 0), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "3) We know its ANGLE OF ROTATION", #White)
      For I = 0 To 63 Step 4
        Angle.F = (#PI / 4.) - ((#PI / 256.) * I)
        DrawArc(ArcX, ArcY, 50., 150., Angle, RGB(64, 0, I), 0., #PI * 2.)
        DrawArc(ArcX, ArcY, 50., 150., Angle, RGB(255, 0, I * 4), ArcAngleStart, ArcAngleEnd)
      Next
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(64, 0, 0), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "4) We know its RADII, (major and minor)", #White)
      For I = 0 To 63 Step 4
        Angle.F = I * 100. / 64.
        DrawArc(ArcX, ArcY, 50. + Angle, 150., 0., RGB(64 - I, 0, 64), 0., #PI * 2.)
        DrawArc(ArcX, ArcY, 50. + Angle, 150., 0., RGB(255 - I * 4, 0, 255), ArcAngleStart, ArcAngleEnd)
      Next
      DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(64, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(255, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(64, 0, 0), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Define.F Ax, Ay, Bx, By, ArcX1, ArcY1, ArcX2, ArcY2
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "5) We know there is TWO WAYS to draw it and a flag controls this...", #White)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleStart, @Ax, @Ay)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleEnd, @Bx, @By)
      CircleEquation(Ax, Ay, Bx, By, 150., @ArcX1, @ArcY1, @ArcX2, @ArcY2)
      DrawArc(ArcX1, ArcY1, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX2, ArcY2, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      
      ;DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(64, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(255, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(64, 0, 0), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "6)From 2 blue points,we search the centers of the 2 blue circles...", #White)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleStart, @Ax, @Ay)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleEnd, @Bx, @By)
      CircleEquation(Ax, Ay, Bx, By, 150., @ArcX1, @ArcY1, @ArcX2, @ArcY2)
      DrawArc(ArcX1, ArcY1, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX2, ArcY2, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      Box(Ax - 4, Ay - 4, 9, 9, RGB(0, 0, 255) )
      Box(Bx - 4, By - 4, 9, 9, RGB(0, 0, 255) )      
      ;DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(64, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(255, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(64, 0, 0), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "7)If equal distances, so equal circles...", #White)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleStart, @Ax, @Ay)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleEnd, @Bx, @By)
      CircleEquation(Ax, Ay, Bx, By, 150., @ArcX1, @ArcY1, @ArcX2, @ArcY2)
      DrawArc(ArcX1, ArcY1, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX2, ArcY2, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      Box(Ax - 4, Ay - 4, 9, 9, RGB(0, 0, 255) )
      DrawArc(Ax, Ay, 150., 150., 0., RGB(0, 128, 0) )
      Box(Bx - 4, By - 4, 9, 9, RGB(0, 0, 255) )      
      DrawArc(Bx, By, 150., 150., 0., RGB(0, 128, 0) )
      ;DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(64, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(255, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(64, 0, 0), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "8)Finding the two green points is finding green circles intersection...", #White)
      DrawText(0, 32, "(It's the reason there is a procedure named CircleEquation() )", #White)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleStart, @Ax, @Ay)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleEnd, @Bx, @By)
      CircleEquation(Ax, Ay, Bx, By, 150., @ArcX1, @ArcY1, @ArcX2, @ArcY2)
      DrawArc(ArcX1, ArcY1, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX2, ArcY2, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      Box(ArcX1 - 4, ArcY1 - 4, 9, 9, RGB(0, 128, 0) )
      Box(ArcX2 - 4, ArcY2 - 4, 9, 9, RGB(0, 128, 0) )
      Box(Ax - 4, Ay - 4, 9, 9, RGB(0, 0, 255) )
      DrawArc(Ax, Ay, 150., 150., 0., RGB(0, 128, 0) )
      Box(Bx - 4, By - 4, 9, 9, RGB(0, 0, 255) )      
      DrawArc(Bx, By, 150., 150., 0., RGB(0, 128, 0) )
      DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(64, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(255, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(64, 0, 0), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "9)If we have these green points we have", #White)
      DrawText(0, 32, "all the necessary to redraw exactly the arc,", #White)
      DrawText(0, 64, "and calculate bounds...", #White)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleStart, @Ax, @Ay)
      GimbalDot(ArcX, ArcY, 150., 150., 0., ArcAngleEnd, @Bx, @By)
      CircleEquation(Ax, Ay, Bx, By, 150., @ArcX1, @ArcY1, @ArcX2, @ArcY2)
      DrawArc(ArcX1, ArcY1, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX2, ArcY2, 150., 150., 0., RGB(0, 0, 64), 0., #PI * 2.)
      Box(ArcX1 - 4, ArcY1 - 4, 9, 9, RGB(0, 128, 0) )
      Box(ArcX2 - 4, ArcY2 - 4, 9, 9, RGB(0, 128, 0) )
      Box(Ax - 4, Ay - 4, 9, 9, RGB(0, 0, 255) )
      DrawArc(Ax, Ay, 150., 150., 0., RGB(0, 128, 0) )
      Box(Bx - 4, By - 4, 9, 9, RGB(0, 0, 255) )      
      DrawArc(Bx, By, 150., 150., 0., RGB(0, 128, 0) )
      DrawArc(ArcX, ArcY, 150., 150., 0., RGB(0, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(64, 0, 64), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., 0., RGB(255, 0, 255), ArcAngleStart, ArcAngleEnd)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(64, 0, 0), 0., #PI * 2.)
      DrawArc(ArcX, ArcY, 50., 150., #PI / 4., RGB(255, 0, 0), ArcAngleStart, ArcAngleEnd)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  Repeat
    ClearScreen(RGB(0, 0, 0) )
    StartDrawing(ScreenOutput() )
      DrawingFont(FontID(0) )
      DrawText(0, 0, "It is the internal fonctionizing of GetArcChars()", #White)
      DrawText(0, 32, "Now I could explain you more easily the step #8", #White)
      DrawText(0, 64, "It's the math algo of CircleEquation(). Could not I do?", #White)
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_Space)
  Repeat
    ExamineKeyboard()
  Until KeyboardPushed(#PB_Key_All) = 0
  CloseScreen()
  
Post Reply