Draw The Sine Wave in LibreOffice BASIC
=======================================
When the Ellipse shape is converted to curve in LibreOffice Draw application,
and you choose to edit points individually, you can see 12 points along
the curve. The difference in angle between two adjacent points is 30
degrees. Between each pair of adjacent points, lie 2 control points.
The total number of points is 37 because the ellipse is a closed curve,
and the last one has the coordinates of the first one.
The angles will be good enough, and will not require trigonometric functions.
And I guess that calculating the control points from the first and second
derivatives at one point will be a good choice[1].

Choosing BASIC
--------------
The reason I choose BASIC is that the built-in editor has syntax highlighting,
and that it includes a debugger. So, locating errors or places where the
behavior is unexpected and undesired is easier.

Getting Started
---------------
To create a new macro, choose from the menubar:
Tools->Macros->Organize Mocros->Basic

In hte BASIC Macros dialog, click "My Macros" and then click the "New" button.
That opens n editor in a new window, and you can see there a new subroutine
with a name like "Macro1". Feel free to change it. The subroutine is created
in "My Macros & Dialohs/Standard/Module 1".
To learn more about Basic, from the editor push F1 for help. From there the way
to other LibreOffice BASIC topic help is short. To find how to work with arrays
or type an hexadecimal value, click Programming with LibreOffice Basic,
then from the page opened click Syntac and then Using Variables.

Starting the Program
--------------------
First, let us define some variables, and populate them with data.
No UNO(Universal Network Objects) objects, yet.
Following is the code that does it:

Sub SineWave
Dim oDoc As Object
   'Data for the macro: define arrays of y-values, first derivatives and second derivatives
   num_cycles=1
   num_normal_points=num_cycles*12 ' Actually it is the number of normal points minus 1
   Dim yvalues(num_normal_points)
   Dim first_derivatives(num_normal_points)
   for i = 0 to  num_normal_points
     if (i >= 12) then
       yvalues(i) = yvalues(i - 12)
       first_derivatives(i) = first_derivatives(i - 12)
     elseif (i >= 6) then
       yvalues(i) = -yvalues(i - 6)
       first_derivatives(i)=-first_derivatives(i - 6)
     elseif (i >= 4) then
       yvalues(i)=yvalues(6 - i)
       first_derivatives(i)=-first_derivatives(6 - i)

     REM Here you populate the values, and multiply by 1000 because the coordinates are of type long.
     REM and we derive with respect to t and not x where t comes from the B(t) Bezzier polynomial.
     elseif (i = 3) then
       yvalues(i) = -1000
       first_derivatives(i) = 0
     elseif (i = 2) then
       yvalues(i) = -int(sqr(3)*500 + 0.5)
       first_derivatives(i) = -int(500 * pi/6 + 0.5)
     elseif (i = 1) then
       yvalues(i) = -500
       first_derivatives(i) = -int(sqr(3) * 500 * pi/6 + 0.5)
     else
       yvalues(i) = 0
       first_derivatives(i) = -int (1000 * pi/6)
     endif
   next i
REM End of code excerpt

Noe, Let Us Populate the Geometry Property
------------------------------------------
The Geometry property is a structure consisting of points before any
transformations (scaling, rotating) take place. The shape chosen for the
sine wave is called OpenBezierShape. You can get to this shape by openiog
page "https://api.libreoffice.com" clicking the link "IDL Reference", then
From the "Classes" dropdown at the top, choosing "Class List".
Then from the tree go to "co./sun.star.drawing.OpenBezierShape". If you
then click on the PolyPolygonBezzierDescriptor" a property named Geometry.
It is a structure of type "com.sun.star.drawing.PolyPolygonBezierCoords",
the structure consists of two members: Coordintes and Flags. Both are
vectors of vectors.

NOTE: Don't assign a bi-dimensional arrays into those members. That won't
work! Instead define a vector whose elements are vectors/
Following is the code that does it:

   DIM geometryPropertyStruct  As  New
   com.sun.star.drawing.PolyPolygonBezierCoords
   last_bezier_point = num_normal_points * 3
   Dim Coordinates(0)
   Dim CoordsVec(last_bezier_point) As New com.sun.star.awt.Point
   Coordinates(0)=CoordsVec
   Dim Flags(0)
   Dim FlagsVec(last_bezier_point)
   Flags(0)=FlagsVec

   x = 0
   thrice_i = 0
   for i=0 to num_normal_points - 1
       CoordsVec(thrice_i).X = x
       CoordsVec(thrice_i).Y = yvalues(i)
       FlagsVec(thrice_i) = com.sun.star.drawing.PolygonFlags.NORMAL
       ' Add the first control point using the derivative and the start point
       ' The formula is: B'(0) = 3(P1 - P0)
       CoordsVec(thrice_i + 1).X = int((1000 * pi/6 + 3*x)/3 + 0.5)
       CoordsVec(thrice_i + 1).Y = int((first_derivatives(i) + 3*yvalues(i))/3 + 0.5)
       FlagsVec(thrice_i + 1) = com.sun.star.drawing.PolygonFlags.CONTROL
       'Add the second control points using the first derivative the end point
       'The formula is B'(1)=3(P3 - P2)
       CoordsVec(thrice_i + 2).X = int(x + 1000*pi/9+0.5)
       CoordsVec(thrice_i + 2).Y = int((3*yvalues(i + 1) - first_derivatives(i+1))/3 + 0.5)
       FlagsVec(thrice_i + 2) = com.sun.star.drawing.PolygonFlags.CONTROL
       x = x + 1000 * pi / 6
       thrice_i = thrice_i + 3
   next i
   CoordsVec(last_bezier_point).X = x
   CoordsVec(last_bezier_point).Y = yvalues(num_normal_points)
   FlagsVec(last_bezier_point) = com.sun.star.drawing.PolygonFlags.NORMAL

   geometryPropertyStruct.Coordinates=Coordinates
   geometryPropertyStruct.Flags=Flags

REM End of code excerpt

Finally, Let Us Add the Shape to the Document
---------------------------------------------
To find how to work with document in Basic. Fo to "https://api/libreoffice.org",
and from the Content, choose "Developer's Guide". Then under "How This Book is
Organized" click on "11. LibreOffice Basic". There, under Writing and Debugging
a Basic UNO program", you will see that the document model is called
"ThisComponent".
Another resource for getting info about the document out of the internet is
a tool named "Development Tools". (Tools->Dvelopment Tools". Then on the left,
click "Document" and then at the top choose Methods. You can find there
methods, such as "getDrawPages". Click Pages on the left and find there
the methods "getCount" and "getByIndex". Expand "Pages" and then choose a
page to see what's in there, etc.
The following code set properties and adds the shape:
   oDoc = ThisComponent
   oDrawPagesSupplier =oDoc.getDrawPages()

   n=oDrawPagesSupplier.getCount()
   drawPage = oDrawPagesSupplier.getByIndex(n-1)
   lineShape = oDoc.createInstance("com.sun.star.drawing.OpenBezierShape")

   lineShape.setPropertyValue("Geometry",geometryPropertyStruct)
   lineShape.setPropertyValue("LineColor",&hff0000)
   aSize=new com.sun.star.awt.Size
   aSize.Width= int(2000 * pi + 0.5)
   aSize.Height=2000
   aPosition=new com.sun.star.awt.Point
   aPosition.X = 1000
   aPosition.Y= 1000
   lineShape.setPosition(aPosition)
   lineShape.setSize(aSize)
   drawPage.add(lineShape)
End Sub

Now, it's time to run and see the result.

[1] gopher://zaibatsu.circumlunar.space/0/~zaphodb/phlog/beziercurvesinlibreoffice.txt