Page 1 of 1

draw a 3D arc

Posted: Sat Jan 23, 2021 8:45 am
by ludoke
how to draw a 3D arc ,startpoint,endpoint ,radius are known.
how to draw a 3D arc ,startpoint,endpoint ,startradius and endradius are known.

And how to rotate this around x,y,z axis ?

Re: draw a 3D arc

Posted: Sat Jan 23, 2021 10:04 am
by kernadec
hi, ludoke
use PureBasic - VectorDrawing

cordially

Re: draw a 3D arc

Posted: Sat Jan 23, 2021 4:23 pm
by Olli
@Ludoke

The simplest way is use Ogre3D.

First, you can use easily the procedure EllipseWithRotation() you can find here.
This procedure allows you to draw into an image.

Second, you apply this image onto a texture, you integrate in a material, you apply onto a plane 3D entity.

Code: Select all

Image --> Texture --> Material --> 3D entity
This allows you to rotate through two ways :
1) quaternion rotation
2) euler rotation

This above is for your first template. For the second template, you have to build a new procedure which is not very different from EllipseWithRotation(). But the best is already start to create the process for the first template.

Re: draw a 3D arc

Posted: Sat Jan 23, 2021 4:52 pm
by Olli
For the 2nd template, here you have 2 new arguments : StartScale and FinishScale.
A pair of values as 1.0 and 1.0 gives exactly the same result as EllipseWithRotation().

I let you test several values to compare.

I wrote it on the fly on my smartphone, without test. The width of the screen is such small as I have not had the choice to divide the large source code lines...

If anybody wants to correct alignement syntax, no problem.

Nice time !

Code: Select all

Procedure EllipticSpiralWithRotation(xCenter.F,
yCenter.F, 
xRadius.F, 
yRadius.F, 
zRotation.F, 
StartAngle.F, 
FinishAngle.F, 
Color.L, 
FinishScale.F, 
StartScale.F = 1.0)

Protected Scale.F
Protected ScaleStep.F
Protected Angle.F
Protected AngleStep.F
Protected AngleDelta.F
Protected ScaleDelta.F
Protected X.F
Protected Y.F
Protected DisplayX.F
Protected DisplayY.F
Protected GreatestRadius.F
If xRadius > yRadius
GreatestRadius.F = xRadius
Else
GreatestRadius = yRadius
EndIf
AngleStep.F = #PI / GreatestRadius
AngleDelta = FinishAngle - StartAngle
ScaleDelta = FinishScale - StartScale
ScaleStep = AngleStep * ScaleDelta / AngleDelta
NewList DrawX.POINT()
Angle = StartAngle
Scale = StartScale
Repeat
X.F = Cos(Angle) * xRadius * Scale
; Draw an ellipse...
Y.F = -Sin(Angle) * yRadius * Scale
DisplayX.F = X * Cos(zRotation) - Y * Sin(zRotation)
; (^ Rotation...)
DisplayY.F = X * Sin(zRotation) + Y * Cos(zRotation)
AddElement(DrawX() )
; Record...
DrawX()\X = xCenter + DisplayX
DrawX()\Y = yCenter + DisplayY
Angle + AngleStep
Scale + ScaleStep
Until Angle > FinishAngle
ResetList(DrawX() )
; Draw...
For i = 1 To CountList(DrawX() ) - 1
SelectElement(DrawX(), i - 1)
x1 = DrawX()\X
y1 = DrawX()\Y
SelectElement(DrawX(), i)
x2 = DrawX()\X
y2 = DrawX()\Y
LineXY(x1, y1, x2, y2, Color)
Next
ClearList(DrawX() )
EndProcedure

Re: draw a 3D arc

Posted: Sat Jan 23, 2021 9:47 pm
by ludoke
thanks,I found this:
Ollivier
Post subject:PostPosted: Tue Aug 28, 2007 10:53 pm

Code: Select all

InitSprite()
  InitKeyboard()
  OpenScreen(1024, 768, 32, "x")
  ;***********
  R.F = 100.0
  Xtheta.F = 0.0
  Ytheta.F = 0.0
  Ztheta.F = 0.0     
  Ttheta.F = 0.0     
  ;***********
  Repeat
    StartDrawing(ScreenOutput() )
      Box(0, 0, 1024, 768, #Black)
      Vxx.F = Cos(Ztheta)
      Vxy.F = -Sin(Ztheta)
      Vyx.F = Cos(Ztheta + #PI / 2.0)
      Vyy.F = -Sin(Ztheta + #PI / 2.0)
      Line(512, 384, Vxx * 20.0, Vxy * 20.0, #Blue)
      Line(512, 384, Vyx * 20.0, Vyy * 20.0, #Blue)
      For i = 0 To 359
        ; MaJ référentiel Vecteur x et Vecteur y
        X.F = #PI * i / 180.0
       
        Tx.F = Cos(X) * Cos(Ytheta) * 100.0
        Ty.F = Sin(X) * 100.0
     
        Ex.F = Vxx * Tx + Vxy * Ty
        Ey.F = Vxy * Tx + Vyy * Ty
        ;Trace vecteur E
        Plot(512 + Ex, 384 + Ey, #Blue)
        If Abs(X - Xtheta) < 0.01
          Line(512, 384, Ex, Ey, #White)
          Box(511 + Ex, 383 + Ey, 3, 3, #White)
        EndIf
       
      Next   
    Xtmp = Xtheta * 180 / #PI
    Xtmp % 180
    DrawText(0, 0, Str(Xtmp), #White, #Black)
    Ytmp = Ytheta * 180 / #PI
    Ytmp % 180
    DrawText(0, 16, Str(Ytmp), #White, #Black)
    ZTmp = (Ztheta * 180 / #PI)
    Ztmp % 180
    DrawText(0, 32, Str(Ztmp), #White, #Black)
    DrawText(0, 48, "ARROW KEYS PageUp PageDown to change x, y, et z values")
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
    If KeyboardPushed(#PB_Key_PageUp)
      Ztheta + 0.04     
    EndIf
    If KeyboardPushed(#PB_Key_PageDown)
      Ztheta - 0.04
    EndIf
    If KeyboardPushed(#PB_Key_Up)
      Xtheta + 0.04
      If Xtheta > 2.0 * #PI
        Xtheta - 2.0 * #PI
      EndIf
    EndIf
    If KeyboardPushed(#PB_Key_Down)
      Xtheta - 0.04
      If Xtheta < 0.0
        Xtheta + 2.0 * #PI
      EndIf
    EndIf
    If KeyboardPushed(#PB_Key_Left)
      Ytheta + 0.04
    EndIf
    If KeyboardPushed(#PB_Key_Right)
      Ytheta - 0.04
    EndIf
  Until KeyboardPushed(#PB_Key_Escape)

Re: draw a 3D arc

Posted: Sat Jan 23, 2021 11:05 pm
by Olli
B...But... But I had however hidden to your eyes !!! :D

It is NOT 3D ! :D

Why? If you want to add the 3rd relative angle, the math op is very very big (more complex than the whole process you find)

The reason? There is an abstracted 'wall' named gimbal lock.

You can try to discover yourself this very difficult wall :

1st absolute Z rotation : no problem, cos aZ and sin aZ

2nd X rotation : no problem, a cos X which is transformed by the 1st op

3rd Y rotation : no problem, but becomes complex, a cos Z which is transformed by the 2nd rotation, itself transformed by the 1st rotation.

4st op (Z rotation) is unabled : Z has a 'dead' rotation effect due to the cancelling angle got by blend of both perpendicular X and Y angles : this is the gimbal lock.


2 ways to solve this lock :

1) Create a Euler referency, and detach the initial 3D angle for every 3D frame. This prevents you to blend relative rotations (X,Y or Z object rotation axises) with absolute rotations (X, Y or Z world rotation axises). This blend is named spherical lerp or slerp.
Cube example --> You can see lots of ops and the slerps (i.e. blend Z object axis with Z world axis smoothly when X and Y object axises are non-zero) are unabled without 3 times more ops than you can see in this example.

2) Create a Hamilton referency (quaternion), with W, X, Y and Z angles in a hyperspace (4D) which allows you to blend relative and absolute rotation (smoke effects, etc...) and convert from quaternion to Euler on every frame.
Quaternion + Euler converting is lightly lighter in ops quantities than Euler referency, but it is again a lot, and Ogre (or, its basis, OpenGL) has this integrated. That is the reason I told you, that using Ogre 3D was the easier way !


If you do not need to use slerp, you can study and make your own version of the Cube example. In this way, Ogre3D is not required.

But if you want (or not) the slerp, Ogre3D has all for that.

Last remark : EllipticSpiralWithRotation() and EllipseWithRotation() procedures have the same process : all is recorded in a X+Y list. This means that on Ogre3D, you can modify these procedure to create a 3D sphere per vertex, or a full mesh viewing, and not to have to use an image to be textured on a 3D plane entity.

Re: draw a 3D arc

Posted: Sun Jan 24, 2021 6:33 pm
by ludoke
Olli, it seems more difficult than I thought.
You're using terms I've never heard of. Euler referency and Hamilton referency (quaternion).
I just thought to find some formulas and fill in the variables and done.
I think it is too ambitious for me

Re: draw a 3D arc

Posted: Sun Jan 24, 2021 7:26 pm
by #NULL
If you just want to 'draw an arc in 3d' then this might be enough:
Drawing3D - Draw commands for 3D Scenes
I didn't test it, but I would think you could draw lines with it on a canvas, and multiple lines can become an arc, though you might need some additional math.

Re: draw a 3D arc

Posted: Sun Jan 24, 2021 7:52 pm
by DK_PETER
ludoke wrote:Olli, it seems more difficult than I thought.
You're using terms I've never heard of. Euler referency and Hamilton referency (quaternion).
I just thought to find some formulas and fill in the variables and done.
I think it is too ambitious for me
Don't be put off. Very few people are up to the standards of Comtois or pf_shadoko.
Keep it VERY simple and do what seems to be working. Fake it, when possible - until you get the hang for 3D.
PureBasic's 3D implementation is fun to work with.

Here's a very simple way to fake the arc in 3D using a torus. :wink:
When you get the hang of the basics, move on to mesh creations, if your math is up for it or do your creations using a 3D object designer tool.

Code: Select all

InitEngine3D()
InitSprite()
InitKeyboard()

Declare.i AssignTexture(StartAngle.i = 0, EndAngle = 360) ;fake everything :-)
ExamineDesktops()
OpenWindow(0, 0, 0, DesktopWidth(0) / DesktopResolutionX(), DesktopHeight(0) / DesktopResolutionY(), "Rotation", #PB_Window_BorderLess)
OpenWindowedScreen(WindowID(0), 0, 0, DesktopWidth(0) * DesktopResolutionX(), DesktopHeight(0) * DesktopResolutionY())
CreateCamera(0, 0, 0, 100, 100)


CreateTorus(0, 0.3, 0.03, 8, 60)
CreateEntity(0, MeshID(0), #PB_Material_None, 0, 0, -3)
AssignTexture() ;Complete

Repeat
  
  Repeat : ev = WindowEvent() : Until  ev = 0
  ExamineKeyboard()
  
  If KeyboardPushed(#PB_Key_X)
    RotateEntity(0, 0.5, 0, 0, #PB_Relative)
  EndIf
  If KeyboardPushed(#PB_Key_Z)
    RotateEntity(0, 0, 0, 0.5, #PB_Relative)
  EndIf
  If KeyboardPushed(#PB_Key_Y)
    RotateEntity(0, 0, 0.5, 0, #PB_Relative)
  EndIf
  If KeyboardReleased(#PB_Key_Space)
    AssignTexture(Random(150, 0), Random(360, 200))
  EndIf
  
  RenderWorld()
  
  FlipBuffers()
  
Until KeyboardPushed(#PB_Key_Escape)

Procedure.i AssignTexture(StartAngle.i = 0, EndAngle = 360) ;fake everything and keep it simple :-)
  If IsTexture(0) = 0
    CreateTexture(0, 360, 20)
  EndIf
  StartDrawing(TextureOutput(0))
  Box(0, 0, 360, 20, $FF000000)
  DrawingMode(#PB_2DDrawing_Gradient)
  FrontColor($FF00FD00) : BackColor($FF007E00)
  LinearGradient(180, 0, 180, 10)
  Box(StartAngle, 0, EndAngle, 10)
  LinearGradient(180, 20, 180, 10)
  Box(StartAngle, 10, EndAngle, 20)
  StopDrawing()
  If IsMaterial(0) = 0
    CreateMaterial(0, TextureID(0))
  Else
    FreeMaterial(0)
    CreateMaterial(0, TextureID(0))
  EndIf
  MaterialBlendingMode(0, #PB_Material_Add)
  MaterialCullingMode(0, #PB_Material_NoCulling)
  SetEntityMaterial(0, MaterialID(0))
EndProcedure


Re: draw a 3D arc

Posted: Sun Jan 24, 2021 10:11 pm
by Olli
CreateTorus()...
I did not know...
Is not that censored ?

Re: draw a 3D arc

Posted: Mon Jan 25, 2021 9:42 am
by MrBean
the most hard part for me is to get the coordinates of the multiple points which constitute the Arc
if we know these points, then it is easy to draw these points and to rotate them using the opengl function glDrawArrays_ . this function operates over a structured array filled with the Arc (or whatever) points data
here is an example to draw 1/4 of the circle and then rotate it arround the circle center
note that glOrtho_(-1,1,-1,1,-1,1) define the viewable 3d scene change it to glOrtho_(-2,2,-2,2,-2,2) the the Arc will appear smaller since the "universe" now is bigger

Code: Select all

Declare CircleData()
Declare DrawData()

Structure PointsXYZ
  x.f
  y.f
  z.f
  r.f ;red
  g.f ;green
  b.f ;blue
  a.f ;alpha
EndStructure


Global Dim Points3D.PointsXYZ(0) ; for the CircleData()

OpenWindow(0, 0, 0, 600, 600, "glDrawArrays ", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

OpenGLGadget(0, 50, 50, 500, 500)
glEnable_(#GL_LINE_WIDTH)
glEnable_(#GL_LINE_SMOOTH);
glHint_(#GL_LINE_SMOOTH_HINT, #GL_NICEST)
;glEnable_(#GL_POINT_SMOOTH);
;glHint_(#GL_POINT_SMOOTH_HINT, #GL_NICEST);

 
CircleData()

;glOrtho_(-2,2,-2,2,-2,2) 
glOrtho_(-1,1,-1,1,-1,1) 
;glMatrixMode_ (#GL_PROJECTION)
Repeat
  
Repeat
  event = WindowEvent()
  
    If event = #PB_Event_CloseWindow
      quit = #True
    EndIf
          
  Until event = 0 Or quit = #True
  glEnable_(#GL_LINE_WIDTH)
  glLineWidth_(2)
  ;glPointSize_(2);
  glRotatef_(1, 0, 1, 0) ;glRotatef_(angle, x, y, z) 
  
  DrawData()  
    
  SetGadgetAttribute(0, #PB_OpenGL_FlipBuffers, #True)
  Delay(5)
Until Event = #PB_Event_CloseWindow Or quit = #True
   
Procedure CircleData()
 Protected.i c
 Protected.f x, y, z, increment, i 
 increment = 0.01
 
 While i < 1/2*#PI ;2*#PI ;for full circle
   ;points color
   Points3D(c)\r = 0 :Points3D(c)\g = 1 :Points3D(c)\b = 0
   ;Parametric Equations of the Circle
   Points3D(c)\x = Cos(i)*1
   Points3D(c)\y = Sin(i)*1 
   Points3D(c)\z = 0
   
    i + increment 
    c + 1
  ReDim Points3D.PointsXYZ(c)      
  Wend
 
 

EndProcedure
 
Procedure DrawData()
  SetGadgetAttribute(0, #PB_OpenGL_SetContext, #True)
  glClearColor_(0.2, 0.2, 0.1, 1.0) ; background color
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
    
  glEnableClientState_(#GL_VERTEX_ARRAY)
  glEnableClientState_(#GL_COLOR_ARRAY)
      
  glVertexPointer_(3, #GL_FLOAT, SizeOf(PointsXYZ), @Points3D(0)\x)
  glColorPointer_(4, #GL_FLOAT, SizeOf(PointsXYZ), @Points3D(0)\r)
      
  ;glDrawArrays_(#GL_LINES, 0, ArraySize(Points3D()))
  ;glDrawArrays_(#GL_POINTS, 0, ArraySize(Points3D()))
  glDrawArrays_(#GL_LINE_STRIP, 0, ArraySize(Points3D()))
                          
  glDisableClientState_(#GL_COLOR_ARRAY)
  glDisableClientState_(#GL_VERTEX_ARRAY)
  
EndProcedure

Re: draw a 3D arc

Posted: Mon Jan 25, 2021 12:54 pm
by juergenkulow
Hello MrBean, hello DK_PETER,

How do I connect the following code to your program?

Code: Select all

; Parameter for arc 
x1.d=ValD(InputRequester("x1","x1:","0.0"))
y1.d=ValD(InputRequester("y1","y1:","0.0"))
z1.d=ValD(InputRequester("z1","z1:","0.0"))
x2.d=ValD(InputRequester("x2","x2:","1.0"))
y2.d=ValD(InputRequester("y2","y2:","1.0"))
z2.d=ValD(InputRequester("z2","z2:","1.0"))
r.d =ValD(InputRequester("r", "r:" ,"0.5"))

Re: draw a 3D arc

Posted: Mon Jan 25, 2021 2:04 pm
by Olli
Hello JürgenKulow,

I apologize not to be Dk_Peter, nor MrBean. But I just want to add, reading your question, a ternary (status 0, 1 or 2) argument is missing in your message.

In fact, to create a 3D referency from 3 points in a 3D space, there is 6 ways. I suppose between these 2 points, it is an ellipse, drawn in a rectangular plane.

An ellipse has, in the minimum, one symetry axis. So 3 of these 6 ways, cancel themselves 2 to 2, by symetry. Results : it stays 3 ways to draw an ellipse between two 3D points.

So, a ternary argument should be added : i.e. X, Y or Z.

A idea of this subtility is imagining your are building a home (strange simple home). Between 2 opposite points, you can build :
- 1: a roof exposed to the South (I choose 1 of the 4 directions)
- 2: a roof exposed to the East (I choose 1 of the 2 directions, perpendicular to the first previous direction)
- 3: a wall

These are so 3 ways available from two 3D points.

Re: draw a 3D arc

Posted: Mon Jan 25, 2021 2:29 pm
by MrBean
@juergenkulow
change the Dim in line 15 to
Global Dim Points3D.PointsXYZ(2)
and replace the CircleData() Procedure as in the following
here is the full modified code, but note to view the rotation better make the universe bigger by changing glOrtho... to glOrtho_(-2,2,-2,2,-2,2)

Code: Select all

Declare CircleData()
Declare DrawData()

Structure PointsXYZ
  x.f
  y.f
  z.f
  r.f ;red
  g.f ;green
  b.f ;blue
  a.f ;alpha
EndStructure


Global Dim Points3D.PointsXYZ(2) ; for the CircleData()

OpenWindow(0, 0, 0, 600, 600, "glDrawArrays ", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

OpenGLGadget(0, 50, 50, 500, 500)
glEnable_(#GL_LINE_WIDTH)
glEnable_(#GL_LINE_SMOOTH);
glHint_(#GL_LINE_SMOOTH_HINT, #GL_NICEST)
;glEnable_(#GL_POINT_SMOOTH);
;glHint_(#GL_POINT_SMOOTH_HINT, #GL_NICEST);
 
CircleData()

;glOrtho_(-2,2,-2,2,-2,2)
glOrtho_(-1,1,-1,1,-1,1)
;glMatrixMode_ (#GL_PROJECTION)
Repeat
 
Repeat
  event = WindowEvent()
 
    If event = #PB_Event_CloseWindow
      quit = #True
    EndIf
         
  Until event = 0 Or quit = #True
  glEnable_(#GL_LINE_WIDTH)
  glLineWidth_(2)
  ;glPointSize_(2);
  glRotatef_(1, 0, 1, 0) ;glRotatef_(angle, x, y, z)
 
  DrawData() 
   
  SetGadgetAttribute(0, #PB_OpenGL_FlipBuffers, #True)
  Delay(5)
Until Event = #PB_Event_CloseWindow Or quit = #True
 
Procedure CircleData()

 ; Parameter for arc
x1.d=ValD(InputRequester("x1","x1:","0.0"))
y1.d=ValD(InputRequester("y1","y1:","0.0"))
z1.d=ValD(InputRequester("z1","z1:","0.0"))
x2.d=ValD(InputRequester("x2","x2:","1.0"))
y2.d=ValD(InputRequester("y2","y2:","1.0"))
z2.d=ValD(InputRequester("z2","z2:","0.0"))
r.d =ValD(InputRequester("r", "r:" ,"1.0"))

   ;Parametric Equations of the Circle
   Points3D(0)\x = x1
   Points3D(0)\y = y1
   Points3D(0)\z = z1
   
   Points3D(1)\x = x2
   Points3D(1)\y = y2
   Points3D(1)\z = z2
      
   Points3D(0)\r = r :Points3D(0)\g = 0 :Points3D(0)\b = 0
   Points3D(1)\r = r :Points3D(1)\g = 0 :Points3D(1)\b = 0
  
EndProcedure
 
Procedure DrawData()
  SetGadgetAttribute(0, #PB_OpenGL_SetContext, #True)
  glClearColor_(0.2, 0.2, 0.1, 1.0) ; background color
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
   
  glEnableClientState_(#GL_VERTEX_ARRAY)
  glEnableClientState_(#GL_COLOR_ARRAY)
     
  glVertexPointer_(3, #GL_FLOAT, SizeOf(PointsXYZ), @Points3D(0)\x)
  glColorPointer_(4, #GL_FLOAT, SizeOf(PointsXYZ), @Points3D(0)\r)
     
  ;glDrawArrays_(#GL_LINES, 0, ArraySize(Points3D()))
  ;glDrawArrays_(#GL_POINTS, 0, ArraySize(Points3D()))
  glDrawArrays_(#GL_LINE_STRIP, 0, ArraySize(Points3D()))
                         
  glDisableClientState_(#GL_COLOR_ARRAY)
  glDisableClientState_(#GL_VERTEX_ARRAY)
 
EndProcedure

Re: draw a 3D arc

Posted: Mon Jan 25, 2021 4:39 pm
by Olli
I cannot test, but sure there is a problem...
I can see GL_LINE_STRIP which requires 4 points, or more... Just GL_LINE set.

And Point3d() array should be bigger than a pair of points which is just a segment, not an arc.

This is a very good example to boot VBO on OpenGL. But it seems that arcs are needed !
:D