How to fit straight line to variable curve and determining the x-intercept - vb.net

I'm trying to figure out how to code a straight line to the straight part of a curve, the curve should look something like the exponential, click the link to open the image:
Straight line to Curve and determining the x-intercept
Here is the code, I'm only using the exponential as an example
`
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim s As String
Dim xl As New Excel.Application
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
wb = xl.Workbooks.Add 'create new workbook
ws = wb.Worksheets(1) 'select sheet 1
ws.Activate()
Dim Currents() As Double
Dim PhotodiodeValues() As Double
Dim AppliedCurrent As Double
'AppliedCurrent = SerialPort1.ReadLine
AppliedCurrent = 0
If AppliedCurrent >= 0 And AppliedCurrent < 0.1 Then
Dim j As Integer = 1
For i As Double = 0 To 5 Step 0.5
ReDim Preserve Currents(j)
ReDim Preserve PhotodiodeValues(j)
MsgBox(i)
MsgBox("LDI " & CType(i, String))
s = ("LDI " & CType(i, String))
AppliedCurrent = i
If AppliedCurrent >= i And AppliedCurrent < (i + 0.1) Then
Currents(j) = CType(i, Double)
Label1.Text = Currents(j)
PhotodiodeValues(j) = CType(Math.E ^ (i), Double)
ws.Cells(j, 1) = Currents(j)
ws.Cells(j, 2) = PhotodiodeValues(j)
Else
System.Threading.Thread.Sleep(1000)
End If
j = j + 1
Next
Else
System.Threading.Thread.Sleep(1000)
End If
sfd1.ShowDialog() 'get file name
wb.SaveAs(sfd1.FileName) 'save data to file
wb.Close()
xl = Nothing 'dispose of excel
ScatterGraph1.PlotXY(Currents, PhotodiodeValues)
'SerialPort1.Close()
End Sub
End Class`

First off, I'll explain my thought process. If I have misunderstood, please let me know and I will update my answer. The slope dy/dx of the curve y = e^x is dy/dx = e^x, a monotonically increasing function of x for all real x. There is never a point at which the function becomes linear and, while it has a horizontal asymptote (y = 0) it has no vertical asymptote.
I take it that what you want is the equation of a tangent line taken at a point where the slope first becomes greater than some cutoff value m*. After that point, the graph of y = e^x "might as well" be a straight line for your intents and purposes.
So, we must first solve the equation m* = dy/dx = e^x for the x at which m* occurs. The range of e^x is all positive real numbers and e^x is monotonically increasing, so any positive real number m* will have a unique solution x*. indeed, x* = ln(m*). Our tangent line will pass through the point (x*, e^x*) and have slope m*. Recall that m* = e^x*, so the point is (ln(m*), m*) and the slope is m*.
With a point and the slope, we can figure out the equation of a line. We have that the slope from the given point to any other point must be m*; so, (y - y*)/(x - x*) = m*. Rearranging, (y - y*) = m*(x - x*), y = mx - mx* + y*, and finally y = mx + (y - mx) = mx + (m - mln(m)). The Y-intercept is therefore (m* - mln(m)). We can get the X-intercept by setting y = 0 and solving for x: 0 = mx + (m - mln(m)), mx = mln(m*) - m*, x = ln(m*) - 1.
In summary:
the equation of the line tangent to y = e^x with slope m* is y = mx + (m - mln(m)).
the Y-intercept of this line is (m* - mln(m)).
the X-intercept of this line is ln(m*) - 1
If the curve is known at compile time, I recommend hard-coding a closed form analytical solution for the derivative and any asymptotes. If the function is not known until runtime, the derivative at a given point can be approximated numerically using a variety of methods. Intuitively, the definition of the derivative as the limit of (f(x+d) - f(x)) / d as d approaches zero can be used to find approximations of the derivative where the derivative (likely) exists. For well-behaved analytic functions, you will typically be safe except in special cases.
If the function's derivative is monotonically non-decreasing, as in this example, you can find the point (if any) at which the function's slope meets or exceeds a certain cutoff using approximation (as above) in conjunction with something akin to binary search. Start at a value such as x = 0, and increase or decrease x by some multiplicatively increasing factor until you have passed your target. Now, with bounds on the values of x between which your target can be found, check the middle of the range, and then either the left or right half recursively until a suitably good x* is found.

Related

How do I move around nodes in a shape?

I am trying to create a Sankey-diagram in Excel, and as a start to this, I am trying to create some "entry arrows" for the left part of the diagram, which will look roughly like this:
I created it by making a chevron arrow, and dragging the rightmost points of it to line up with the tip of the arrow.
Now, to do this for all the arrows I need, I want to do this programmatically, but I can't figure out if there is any way to do much with the nodes (?) of the shape. Trying to record a macro gave me nothing.
This is what I have so far, the macro aborts on the Debug.Print line, probably because the node object doesn't have a Left property :P
Sub energiInn()
Dim r As Range, c As Range
Dim lo As ListObject
Dim topp As Double, høgde As Double
Dim i As Long, farge As Long
Dim nd As Object
Set lo = Tabell.ListObjects("Energi_inn_elektrolyse")
Set r = lo.DataBodyRange
topp = 50
With SankeyDiagram.Shapes
For i = 1 To r.Rows.Count
høgde = Application.WorksheetFunction.Max(10, r.Cells(i, 2) / 50#)
With .AddShape(Type:=msoShapeChevron, Left:=50, top:=topp, Width:=200, Height:=høgde)
.Name = r.Cells(i, 1)
farge = fargekart((i - 1) Mod UBound(fargekart))
.Fill.ForeColor.RGB = RGB(farge Mod 256, (farge \ 256) Mod 256, farge \ 65536)
For Each nd In .Nodes
Debug.Print nd.Left
Next nd
End With
topp = topp + høgde
Next i
End With
Debug.Print r.Address
End Sub
Honestly, I am unsure if this can be done at all, but even if it is impossible, it would be nice to get it confirmed :)
What you're looking for is .Nodes.SetPosition. Because it's relative positioning, this can be a challenge. You need to use the objects position elements to make sure the points are moving in relation to the shape.
With .AddShape(Type:=msoShapeChevron, Left:=50, Top:=topp, Width:=200, Height:=høgde)
.Name = r.Cells(i, 1)
.Nodes.SetPosition 2, .Left + .Width, .Top
.Nodes.SetPosition 4, .Left + .Width, .Top + .Height
First argument is the node index. Next is the x position, which we want all the way to the right of the graphic, so we add the shapes position left to the width of the shape. Last is the y position, first point we want in the topmost corner, so we use the shapes top. Last point, we add the height to the top position to bring to the bottom corner.
I believe it would be more simple drawing this as free form using Shapes.BuildFreeform Method and then converting to shape using FreeformBuilder.ConvertToShape Method.
Example:
Sub drawEntryArrow()
Dim x1 As Single, y1 As Single, w As Single, h As Single
Dim oShape As Shape
x1 = 10
y1 = 10
w = 200
h = 200
With ActiveSheet.Shapes.BuildFreeform(msoEditingAuto, x1, y1)
.AddNodes msoSegmentLine, msoEditingAuto, x1 + w, y1
.AddNodes msoSegmentLine, msoEditingAuto, x1 + w, y1 + h
.AddNodes msoSegmentLine, msoEditingAuto, x1, y1 + h
.AddNodes msoSegmentLine, msoEditingAuto, x1 + w / 2, y1 + h / 2
.AddNodes msoSegmentLine, msoEditingAuto, x1, y1
Set oShape = .ConvertToShape
End With
End Sub
If you just want to get rid of the point at the right, you can simply delete the node (nodes of a chevron are counted clockwise starting at the top left):
.Nodes.Delete 3
To get access to all nodes with the nodes-property of a shape, however, as long as you deal with a standard shape type, you can't access the coordinates.
When you use the "edit points", a shape changes its type to msoShapeNotPrimitive - but I couldn't figure out how to do this using VBA.
UPDATE
Played around a bit (because I'm curious) - just as an example if someone wants to change a shape manually:
' First change Shape Type:
' WILL NOT WORK: sh.AutoShapeType = msoShapeNotPrimitive
' Instead, add a node and remove it immediately. This changes the shape type.
.Nodes.Insert c, msoSegmentLine, msoEditingCorner, 100, 100
.Nodes.Delete c + 1
' Now access the x-coordinate of node 2 and the y-coordinate of node 3
' (note that we cannot access the coordinates directly)
Dim pointsArray() As Single, x As Single, y As Single
pointsArray = .Nodes(2).Points
x = pointsArray(1, 1)
pointsArray = .Nodes(3).Points
y = pointsArray(1, 2)
' Now change the x-value of node 3
sh.Nodes.SetPosition 3, x, y

Is there an alternative way to dynamically create this array of double values?

I am developing a VBA macro to use in AutoCAD. At the moment it converts a circle into a 3D polyline and in itself it is working perfectly. It is just the start and I will be able to put some flesh on the final routine.
This is the VBA macro:
Sub CircleToPolyline()
Dim objSel As AcadEntity
Dim myCircle As AcadCircle
Dim pickedPoint As Variant
' Get the user to select a circle
' Eventually we will use a Selection Set with Filtering to pick them all in the drawing
Call ThisDrawing.Utility.GetEntity(objSel, pickedPoint, "Select Circle:")
If objSel.ObjectName <> "AcDbCircle" Then GoTo SKIP
Set myCircle = objSel
Dim dAngle As Double, dAngleStep As Double, dMaxAngle As Double
dAngle = 0# ' We always start at 0 degrees / radians
dAngleStep = 0.17453293 ' This is 10 degrees in radians
dMaxAngle = 6.28318531 ' This is 360 degrees in radians
' So our polyline will always have 36 vertices
Dim ptCoord() As Double
Dim ptProject As Variant
Dim i As Integer
i = 0
While dAngle < dMaxAngle
ReDim Preserve ptCoord(0 To i + 2) ' Increase size of array to hold next vertex
' Calculate the next coordinate on the edge of the circle
ptProject = ThisDrawing.Utility.PolarPoint(myCircle.center, dAngle, myCircle.Radius)
' Add to the coordinate list
ptCoord(i) = ptProject(0)
ptCoord(i + 1) = ptProject(1)
ptCoord(i + 2) = ptProject(2)
' Increment for next coordinate/angle on the circle edge
dAngle = dAngle + dAngleStep
i = i + 3
Wend
' Create the 3D polyline
Dim oPolyline As Acad3DPolyline
Set oPolyline = ThisDrawing.ModelSpace.Add3DPoly(ptCoord)
oPolyline.Closed = True
oPolyline.Update
SKIP:
End Sub
I am just wondering if there are any alternative methods for managing my dynamic array (ptCoord)? For example, is there any way that I can just add the ptProject into a dynamic list and then just use this list in the Add3dPoly routine?
The thing is, PolarPoint returns a variant. And ptCoord is a array of doubles (which is what Add3dPoly expects). This is why I have done it like this. I have not used variants (except for handling return values).
My code is quite simple and sufficient, but if it can be further simplified I would be interested in knowing (given the context of VBA and AutoCAD environment).
I hope my question is clear. Thank you.
It is feasible to allocate a chunk of memory and write the sequential results of each of your PolarPoint calls to it. You could then copy that memory to your ptCoord array in one call. However, the APIs are very awkward, there'd be a lot of fiddling with pointers (never straightforward in VBA) and most memory coding errors result in a complete Excel crash. For 108 data points it doesn't seem worth the effort.
I'd say your notion of iterating each of the result arrays and writing them individually to ptCoord is as good a way as any.
Your comments
'We always start at 0 degrees / radians, and 'So our polyline will always have 36 vertices
suggest your ptCoord array will have a fixed dimension (ie 36 * 3). If that's the case couldn't you just dimension the array once? Even if you want to vary the number of degrees to draw through, you could still dimension your array at (n * 3) without having to ReDim Preserve on every iteration.
A snippet of your code could therefore become:
Dim alpha As Double
Dim index As Integer
Dim i As Integer
Dim ptCoord(0 To 107) As Double
Dim ptProject() As Double
Dim pt As Variant
...
For i = 0 To 35
ptProject = ThisDrawing.Utility.PolarPoint(myCircle.center, dAngle, myCircle.Radius)
For Each pt In ptProject
ptCoord(index) = pt
index = index + 1
Next
alpha = alpha + 0.174532925199433
Next
Your code appears good to me, I was going to suggest a two dimensional array: -
Dim ptCoord(2,0)
...
ptCoord(0,0) = ptProject(0)
ptCoord(1,0) = ptProject(1)
ptCoord(2,0) = ptProject(2)
ReDim Preserve ptCoord(2,1)
ptCoord(0,1) = ptProject(0)
ptCoord(1,1) = ptProject(1)
ptCoord(2,1) = ptProject(2)
The second dimension in a two dimensional array can be dynamically re-dimensioned. But I'm not sure this will save you anything and it may not work with Add3DPoly.
You could use UBound to save on the i variable.
ReDim Preserve ptCoord(UBound(ptCoord,1)+3)
In the above I haven't declared the lower/base (0 To) as 0 is the default base, I have then used UBound (Upper bound) to get the size of the array and added 3 to that to make it 3 larger.
UBound([Array],[Dimension])
Array being the array you want to check
Dimension being the dimension you want to check the size on, it has a base of 1 not 0 (so the first dimension is 1 not 0, the second is 2 not 1, and so on...)
You can omit Dimension and the first will be assumed.
To access it without i you could use: -
ptCoord(UBound(ptCoord,1)-2) = ptProject(0)
ptCoord(UBound(ptCoord,1)-1) = ptProject(1)
ptCoord(UBound(ptCoord,1)) = ptProject(2)
you can skip arrays dimming altogether by use of AppendVertex() method
Option Explicit
Sub CircleToPolyline()
Dim myCircle As AcadCircle
Dim circleCenter As Variant, circleRadius As Double
Dim dAngle As Double, dAngleStep As Double, dMaxAngle As Double
Dim oPolyline As Acad3DPolyline
'Get the user to select a circle
Set myCircle = GetCircle(circleCenter, circleRadius)
If myCircle Is Nothing Then Exit Sub
dAngle = 0# ' We always start at 0 degrees / radians
dAngleStep = 0.17453293 ' This is 10 degrees in radians
dMaxAngle = 6.28318531 ' This is 360 degrees in radians
Set oPolyline = GetStarting3dPoly(circleCenter, circleRadius, dAngle, dAngleStep) ' Create the 3D polyline with first two points
Do While dAngle + dAngleStep <= dMaxAngle
dAngle = dAngle + dAngleStep ' Increment for next coordinate/angle on the circle edge
oPolyline.AppendVertex ThisDrawing.Utility.PolarPoint(circleCenter, dAngle, circleRadius) 'append a new vertex
Loop
'finish the polyline
oPolyline.Closed = True
oPolyline.Update
End Sub
Function GetStarting3dPoly(circleCenter As Variant, circleRadius As Double, dAngle As Double, dAngleStep As Double) As Acad3DPolyline
Dim ptCoord(0 To 5) As Double
Dim ptCoords As Variant
ptCoords = ThisDrawing.Utility.PolarPoint(circleCenter, dAngle, circleRadius)
ptCoord(0) = ptCoords(0)
ptCoord(1) = ptCoords(1)
ptCoord(2) = ptCoords(2)
dAngle = dAngle + dAngleStep
ptCoords = ThisDrawing.Utility.PolarPoint(circleCenter, dAngle, circleRadius)
ptCoord(3) = ptCoords(0)
ptCoord(4) = ptCoords(1)
ptCoord(5) = ptCoords(2)
Set GetStarting3dPoly = ThisDrawing.ModelSpace.Add3DPoly(ptCoord)
End Function
Function GetCircle(circleCenter As Variant, circleRadius As Double) As AcadCircle
Dim objSel As AcadEntity
Dim pickedPoint As Variant
' Get the user to select a circle
' Eventually we will use a Selection Set with Filtering to pick them all in the drawing
ThisDrawing.Utility.GetEntity objSel, pickedPoint, "Select Circle:"
If objSel.ObjectName = "AcDbCircle" Then
Set GetCircle = objSel
circleCenter = objSel.Center
circleRadius = objSel.Radius
End If
End Function
as you see I also extracted some actions from the main code and confined them into functions, so to improve further enhancing of your code and its functionalities

Integer subtraction and looping based on integer values

I'm having two problems here. First off all I want to x to change values to x - y and if the new X is higher then 0 i want the process to repeat itself. I've worked out the code below but i'm not certiant on two things.
Am I even allowed to make the equation x = x - y or does this mess up everything? I mean in mathematical terms it would not be possible but if we take X as Hp and Y as damage I want the damage to add up. I don't want it to create an "damage HP" integer for every subtraction as I even don't know how many "Z = x - y" style equations I would have to create if I set Y to be random.
My guess is that I could create a Z integral that would copy X a moment before the subtraction would go off and then have the subtraction be X = Z - Y but I'm not sure how I would go about coding this.
I want it to go ahead and loop itself if X is higher then 0 and I'm not sure if I coded that correctly.
Here is my code:
Module Module1
Dim A As Integer
Dim B As Integer
Dim x As Integer
Dim y As Integer
Sub Main()
End Sub
Sub Maths()
A = 5
B = 4
x = 3
y = 1
Subtraction()
Console.WriteLine("You deal {0} damage to your enemy reducing it to {1} hp.", y, x)
Do Until x <= 0
Loop
End Sub
Private Sub Subtraction()
If A > B Then x = x -y
Return
End Sub
End Module
I liked this question. Here's my thoughts:
Yes, x = x - y is perfectly valid code. It's no different than if I had a string variable named myRunOnSentence and I wanted to concatenate the string that was already in the variable and another string and then store the results back in the string variable. Like this: myRunOnSentence = myRunOnSentence + "another string" Same concept, just change the datatype to an Integer. x = x + y. That programatically says: "take the value in x and the value in y, add them together, and store the result of that expression in x."
You did indeed make a mistake with the loop. You don't have any code inside the body of the loop itself.
You have nothing happening in the Main() sub of your module so this module when run will do nothing. You should just take the code from the Maths() method and put it in the Main() sub.
In your Subtraction() method, A > B will always evaluate to True because A and B are initialized with values and then never changed.
Your code should look something like this:
Module Module1
Dim A As Integer = 5
Dim B As Integer = 4
Dim x As Integer = 3
Dim y As Integer = 1
Sub Main()
Do Until x <= 0
Subtraction()
Console.WriteLine("You deal {0} damage to your enemy reducing it to {1} hp.", y, x)
Loop
End Sub
Private Sub Subtraction()
If A > B Then x = x - y 'Return statement wasn't needed.
End Sub
End Module
If this answered your question, please don't forget to mark it as the answer.

Calculation of minimum distance between coordinate points

I am having a problem in building up VBcode for getting the minimum distance between a set of coordinate points. What I am actually trying is to find the minimum distance between one set of coordinate points (A(x1,y1),Bx2,y2),C(x3,y3),D(x4,y4),E(x5,y5)) with respect to another set of coord points (i(x1,y1),j(x2,y2),k(x3,y3),l(x4,y4),m(x5,y5)).
I hope you understand what I am trying to interpret.
Can anybody help me out?
Public Function DoSearch(ByVal SearchCritera As Bracket, ByVal ListToSearchFrom As System.Collections.Generic.List(Of TRacksDefinitions.Racks.Bracket)) As System.Collections.Generic.List(Of TRacksDefinitions.Search.SearchBracket) Implements TRacksDefinitions.Search.ISearch.DoSearch
_results.Clear()
For Each b As Bracket In ListToSearchFrom
'LAST POINT DISTANCE., WT DIST, number of points, similarity of points (-1 if not used),
Dim dist() As Double = {0, 0, 0, 0, 0}
Dim dx As Double = b.RearPoints(b.RearPoints.Length - 2).X - SearchCritera.RearPoints(SearchCritera.RearPoints.Length - 2).X
Dim dy As Double = b.RearPoints(b.RearPoints.Length - 2).Y - SearchCritera.RearPoints(SearchCritera.RearPoints.Length - 2).Y
Dim dz As Double = b.RearPoints(b.RearPoints.Length - 2).Z - SearchCritera.RearPoints(SearchCritera.RearPoints.Length - 2).Z
dist(0) += Math.Sqrt(dx ^ 2 + dy ^ 2 + dz ^ 2)
dist(1) += Math.Abs(SearchCritera.Wallthickness - b.Wallthickness)
dist(2) += Math.Abs(SearchCritera.RearPoints.Count - b.RearPoints.Count)
If SearchCritera.RearPoints.Count = b.RearPoints.Count Then
Dim d1, d2 As Decimal
' Dim sum As Double = 0
For i As Integer = 0 To b.RearPoints.Count - 1
d1 = Math.Abs(SearchCritera.RearPoints(i).X - b.RearPoints(i).X)
d2 = Math.Abs(SearchCritera.RearPoints(i).Y - b.RearPoints(i).Y)
?????????????????
Next
Else
dist(3) = -1
End If
#LarsTech
The above is code which I have created until now and the next step is calculating the min distance criteria.
Search criteria: rear points is the one we get from solidworks and b.rearpoints is the one present in database we compare both of them find the one which is very similar to the one in database.
You need a distance formula:
Public Function GetDistance(ByVal startPoint As Point, ByVal endPoint As Point) As Integer
Return Math.Sqrt((Math.Abs(endPoint.X - startPoint.X) ^ 2) + _
(Math.Abs(endPoint.Y - startPoint.Y) ^ 2))
End Function
Then you just need to loop through all of your points to find which distance is the smallest:
Dim listOne As New List(Of Point)
listOne.Add(New Point(10, 10))
listOne.Add(New Point(20, 20))
listOne.Add(New Point(30, 30))
listOne.Add(New Point(40, 40))
listOne.Add(New Point(50, 50))
Dim listTwo As New List(Of Point)
listTwo.Add(New Point(50, 10))
listTwo.Add(New Point(50, 20))
listTwo.Add(New Point(50, 30))
listTwo.Add(New Point(50, 40))
'listTwo.Add(New Point(50, 50))
Dim minDistance As Nullable(Of Integer)
For Each p1 As Point In listOne
For Each p2 As Point In listTwo
Dim distance As Integer = GetDistance(p1, p2)
If minDistance Is Nothing OrElse distance < minDistance Then
minDistance = distance
End If
Next
Next
MessageBox.Show("Minimum Distance = " & minDistance.ToString)
In two dimensions, depending upon the distribution of the points, if N exceeds 9, it may make sense to partition the space into int(sqrt(N)-1)^2 identically-sized "boxes". If any box contains more than a hundred or so points, randomly pick ten or so points from the most populous box, find the smallest distance between any pair, and then repartition with a box size of either that smallest distance or a box size reduced by a factor of int(sqrt(k)-1) where k is the population of that box [if a box contains that many points, there must be two within that fraction of the box size.
In the worst case this algorithm could perform badly, since there could be a very dense concentration of points that somehow never get arbitrarily chosen for the distance test, and it could take awhile before the space gets subdivided finely enough to separate them. In practice, however, the points would likely get chosen at some point, allowing the collection to get quickly subdivided.

Calculate angle of two points on Line chart

I want to get the angle of two points on a Line chart.
I know how to calculate an angle, the problem is that I need the x and y of the seriescollection.point and I have no idea how to get it.
Can someone help me with it?
EDIT:
Jean-François Corbett showed me how to get the points, I meant from top and left, and not point on the graph (on X scale and Y scale) though it can work.
I calculate it wrong. how can I calculate the angles in the picture below?
You ask how to get the (x,y) coordinates of points in a chart series. Here is how:
Dim c As Chart
Dim s As Series
Dim x As Variant
Dim y As Variant
Set c = ActiveChart
Set s = c.SeriesCollection.Item(1)
x = s.XValues
y = s.Values
EDIT As far as I can tell from the edited question, OP now wants the pixel coordinates of each point, with origin at the top left of the plot. To do so, you just need to scale by the axis width and span. The x axis is a bit tricky in the case of line plots (which I hate), because there is no min or max scale property; have to use the number of "categories" instead. The following code does this scaling:
Dim c As Chart
Dim s As Series
Dim xa As Axis
Dim ya As Axis
Dim x As Variant
Dim y As Variant
Dim i As Long
Set c = ActiveChart
Set s = c.SeriesCollection.Item(1)
Set xa = c.Axes(xlCategory)
Set ya = c.Axes(xlValue)
x = s.XValues
y = s.Values
For i = LBound(x) To UBound(x)
' Scale x by number of categories, equal to UBound(x) - LBound(x) + 1
x(i) = (i - LBound(x) + 0.5) / (UBound(x) - LBound(x) + 1) * xa.Width
' Scale y by axis span
y(i) = ya.Height - y(i) / (ya.MaximumScale - ya.MinimumScale) * ya.Height
Next i
Note that y increases along the negative y direction on the plot, since you want the origin to be at the top left.
Using this x and y, you can calculate your angle as seen on the screen.
The X and Y values are not directly accessible from the Point object, (as best as I can tell), but they represent actual values passed to the graph. Try accessing them from the worksheet where they are stored.
If that is unavailable, try Series.values, which returns an array of Y-values, and Series.XValues, which returns an array of X-values. (See MSDN Reference)