draw a 3D arc

Everything related to 3D programming
ludoke
Enthusiast
Enthusiast
Posts: 153
Joined: Fri Jul 08, 2016 5:35 pm
Location: Essen (Belgium)

draw a 3D arc

Post 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 ?
User avatar
kernadec
Enthusiast
Enthusiast
Posts: 146
Joined: Tue Jan 05, 2010 10:35 am

Re: draw a 3D arc

Post by kernadec »

hi, ludoke
use PureBasic - VectorDrawing

cordially
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: draw a 3D arc

Post 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.
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: draw a 3D arc

Post 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
ludoke
Enthusiast
Enthusiast
Posts: 153
Joined: Fri Jul 08, 2016 5:35 pm
Location: Essen (Belgium)

Re: draw a 3D arc

Post 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)
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: draw a 3D arc

Post 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.
ludoke
Enthusiast
Enthusiast
Posts: 153
Joined: Fri Jul 08, 2016 5:35 pm
Location: Essen (Belgium)

Re: draw a 3D arc

Post 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
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: draw a 3D arc

Post 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.
User avatar
DK_PETER
Addict
Addict
Posts: 898
Joined: Sat Feb 19, 2011 10:06 am
Location: Denmark
Contact:

Re: draw a 3D arc

Post 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

Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: draw a 3D arc

Post by Olli »

CreateTorus()...
I did not know...
Is not that censored ?
MrBean
User
User
Posts: 17
Joined: Sat Dec 22, 2012 7:27 am

Re: draw a 3D arc

Post 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
juergenkulow
Enthusiast
Enthusiast
Posts: 544
Joined: Wed Sep 25, 2019 10:18 am

Re: draw a 3D arc

Post 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"))
Please ask your questions, because switch on the cognition apparatus decides on the only known life in the universe.Wersten :DDüsseldorf NRW Germany Europe Earth Solar System Flake Bubble Orionarm
Milky Way Local_Group Virgo Supercluster Laniakea Universe
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: draw a 3D arc

Post 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.
MrBean
User
User
Posts: 17
Joined: Sat Dec 22, 2012 7:27 am

Re: draw a 3D arc

Post 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
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: draw a 3D arc

Post 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
Post Reply