Is it possible to programmatically edit the Bezier control handles for the node of a Microsoft Office shape?

Microsoft Office applications allow you to edit the node points of shapes as illustrated below:
Bezier control handlesEach node is defined by a set of 3 coordinates. X1 & Y1 defined the location of the node point while X2 & Y2 and X3 & Y3 define the location of the two Bezier control handles. By right clicking on a freeform shape and selecting Edit Points all 3 coordinated for a given node can be changed.

It's possible to create a new shape programmatically and specify the optional Bezier handles using the AddNodes method:
AddNodes method
It's also possible to change the node coordinates for an existing shape using the SetPosition method:
SetPosition method
But I can't see any way to edit the X2,Y2,X3,Y3 coordinated for the Bezier handles anywhere in the Object Model. Is it possible to read and write these values for an existing shape?
LVL 16
Jamie GarrochSenior Technical Consultant at BrightCarbonAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Claire StrebSoftware GuruCommented:
Yes, you get the Shape.Nodes collection which is a ShapeNodes object (, wich is a collection of ShapeNode objects (, and then you can do things like:

Dim freeFormBuilder As FreeformBuilder
Dim mySlide As Slide
Set mySlide = ActivePresentation.Slides(ActiveWindow.View.Slide.SlideIndex)
Set freeFormBuilder = mySlide.Shapes.BuildFreeform(msoEditingCorner, 266.8235, 104.3088)
With freeFormBuilder
    .AddNodes msoSegmentLine, msoEditingAuto, 536.6986, 89.93378
    .AddNodes msoSegmentLine, msoEditingAuto, 521.4486, 288.4338
    .AddNodes msoSegmentLine, msoEditingAuto, 484.1986, 288.4338
    .AddNodes msoSegmentLine, msoEditingAuto, 484.1986, 308.1838
    .AddNodes msoSegmentLine, msoEditingAuto, 454.5735, 288.4338
    .AddNodes msoSegmentLine, msoEditingAuto, 289.5735, 288.4338
    .AddNodes msoSegmentLine, msoEditingAuto, 266.8235, 104.3088
End With

Dim myShape As Shape
Set myShape = freeFormBuilder.ConvertToShape
'Now you can do a bunch of stuff with myShape, such as myShape.Fill, myShape.TextFrame, etc.
'and the nodes can be examined and changed such as the following (which can be see here even though it is Excel,
With myShape.Nodes
    pointsArray = .Item(1).Points
    currXvalue = pointsArray(1, 1)
    currYvalue = pointsArray(1, 2)
    .SetPosition 1, currXvalue + 1, currYvalue
    .SetPosition 1, currXvalue, currYvalue
End With

Open in new window

Jamie GarrochSenior Technical Consultant at BrightCarbonAuthor Commented:
Thanks for the code examples Claire. What I'm looking for is the points array for X2,Y2 and X3,Y3. The second part of your code access the node location only via the X1,Y1 properties. I can't find out how to read & write the coordinates for the two Bezier handles.
Claire StrebSoftware GuruCommented:
I was giving you examples and references thinking you could extrapolate it from there.  With myShape.Nodes is iterating all of the nodes.  Did you try it?
Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

Jamie GarrochSenior Technical Consultant at BrightCarbonAuthor Commented:
Hi Claire. I had already tried quite a few variations of the code I originally posted which is similar to what you provided and have been unable to expose the 3 sets of coordinated for a single node (X1-X3 & Y1-Y3). The issue seems to be that the points array only contains X1 & Y1. Are you able to read all 6 coordinate properties for each node somehow?
Claire StrebSoftware GuruCommented:
If you had copied and pasted my code above and put a break point on line 19, you would have seen the number of myShape.Nodes.

in other words:

Dim xColumns as String: xColumn = ""
Dim yColumns as String: yColumn = ""
Dim myNode as ShapeNode
For each myNode in myShape.Nodes
    xColumns = xColumns & myNode.Points(1, 1) & ","
    yColumns = yColumns & myNode.Points(1, 2) & ","
xColumns = Left(xColumns, Len(xColumns) - 1)
yColumns = Left(yColumns, Len(yColumns) - 1)
Dim xValues as Variant: xValues = Split(xColumns, ",")
Dim yValues as Variant: yValues = Split(yColumns, ",")
Dim i as Integer
For i = 0 to myShape.Nodes.Count
    Debug.Print "(X" & i+1 & ",Y" & i+1 & ") = (" & xValues(i) & "," & yValues(i) & ")"
Next i

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Jamie GarrochSenior Technical Consultant at BrightCarbonAuthor Commented:
Ahhh. Lightbulb moment. I had incorrectly assumed that a node on a freeform shape comprised three pairs of coordinates. One pair for the point on the path and two points for the two Bezier control handles. That assumption came from the AddNodes method which has 6 coordinate properties. But in reality, this method creates one, two or three nodes depending on how it's used.

So in my original illustration, not only are there 4(+1) nodes for the 4 points of the path but there are 12 additional nodes that describe the Bezier handles:

Bezier control handles are nodes
So there is no API to get the point coordinates and the two Bezier handle coordinates from a single "Node" object because in fact, they are all nodes in the nodes collection for the shape object. Doh!

Thank you for sticking with me Claire :-)

FYI, I updated your code snippet for anyone else looking as the Nodes collection enumerates from 1 and not 0:

Sub ShowAllNodes(Optional myShape As Shape)
  Dim xColumns As String: xColumns = ""
  Dim yColumns As String: yColumns = ""
  Dim myNode As ShapeNode
  If myShape Is Nothing Then Set myShape = ActiveWindow.Selection.ShapeRange(1)
  For Each myNode In myShape.Nodes
    xColumns = xColumns & myNode.points(1, 1) & ","
    yColumns = yColumns & myNode.points(1, 2) & ","
  xColumns = Left(xColumns, Len(xColumns) - 1)
  yColumns = Left(yColumns, Len(yColumns) - 1)
  Dim xValues As Variant: xValues = Split(xColumns, ",")
  Dim yValues As Variant: yValues = Split(yColumns, ",")
  Dim i As Integer
  For i = 1 To myShape.Nodes.Count
    Debug.Print "(X" & i & ",Y" & i & ") = (" & xValues(i - 1) & "," & yValues(i - 1) & ")"
  Next i
End Sub

Open in new window

This free PowerPoint resource file is why I needed to understand this part of the OM.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Office

From novice to tech pro — start learning today.