It has been noted/discussed in at least two other threads that shaping operations (Weld, Trim, Boundary, etc.) can sometime produce content that will initially have correct geometry, but that can unexpectedly become distorted when some types of node editing operations are performed.
Annoying bug when working with curvers!
Nodes convert on weld, objects distort when nodes moved
My observations are that this has to do with nodes that were Symmetrical nodes before the shaping operation, but should have been changed to Smooth nodes as a result of the shaping operation. These nodes cannot be Symmetrical and produce the correct geometry, but they are still identified as being Symmetrical. Note in this screenshot that the node is identified as being Symmetrical, but the control points are not equal distances away from the node (as they should be if a node is Symmetrical).
If certain node editing operations are performed, such nodes appear to "wake up" and assert their Symmetrical identity - which distorts the geometry.One way to work around this is to perform the shaping operation, then manually find every such node and change it from Symmetrical to Smooth. Depending on the complexity of the shape, that might be very tedious.As a less-tedious workaround, here is a VBA macro I wrote that checks each node in a Curve that is identified as Symmetrical. If the control points are not equal distances from the node, then that node is considered to be a "bogus" Symmetrical node, and is changed to Smooth.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
Option Explicit Sub fix_bogus_symmetrical_nodes() Dim sr As ShapeRange Dim s As Shape Dim nodeThis As Node Const dblLengthToleranceTenthMicrons As Double = 50 Dim lngNodesChangedCounter As Long Const strMacroName As String = "Fix Bogus Symmetrical Nodes" On Error GoTo ErrHandler EventsEnabled = False Optimization = True ActiveDocument.BeginCommandGroup "Fix Bogus Symmetrical Nodes" Set sr = ActiveSelectionRange If sr.Count = 1 Then If sr(1).Type = cdrCurveShape Then Set s = sr(1) For Each nodeThis In s.Curve.Nodes If nodeThis.Type = cdrSymmetricalNode Then If Abs(nodeThis.PrevSegment.EndingControlPointLength - nodeThis.NextSegment.StartingControlPointLength) > ActiveDocument.ToUnits(dblLengthToleranceTenthMicrons, cdrTenthMicron) Then nodeThis.Type = cdrSmoothNode lngNodesChangedCounter = lngNodesChangedCounter + 1 End If End If Next nodeThis MsgBox "Number of nodes changed: " & lngNodesChangedCounter, vbInformation, strMacroName Else MsgBox "Selection is not a Curve.", vbInformation, strMacroName End If Else MsgBox "Exactly one Curve shape must be selected.", vbInformation, strMacroName End If ExitSub: ActiveDocument.EndCommandGroup Optimization = False EventsEnabled = True Exit Sub ErrHandler: MsgBox "Error occured: " & Err.Description Resume ExitSub End Sub
That same code is in the .GMS file in this.ZIP archive:
JQ_Fix_Bogus_Symmetrical_Nodes - GMS in ZIP
Here is a short video showing an example of a situation where this bug shows up, and how changing those "bogus" Symmetrical nodes to Smooth can be used to correct the problem:
VIDEO: Fix Bogus Symmetrical Nodes
.
Thing two: my earlier approach to this does not work if the Curve contains two or more consecutive "bogus" Symmetrical nodes.
It plays out something like this:
So, a different, "two-pass" approach can be used:
The code looks like this now:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
Sub fix_bogus_symmetrical_nodes() Dim sr As ShapeRange Dim s As Shape Dim nodeThis As Node Const dblAngleTolerance As Double = 0.001 Const dblLengthToleranceTenthMicrons As Double = 50 Dim action_arr() As String Dim controlpoints_arr() As Double Dim lngNodeIndex_getting As Long Dim lngNodeIndex_setting As Long Dim lngNodesChangedToCuspCount As Long Dim lngNodesChangedToSmoothCount As Long Const strMacroName As String = "Fix Bogus Symmetrical Nodes" On Error GoTo ErrHandler EventsEnabled = False Optimization = True ActiveDocument.BeginCommandGroup "Fix Bogus Symmetrical Nodes" Set sr = ActiveSelectionRange If sr.Count = 1 Then If sr(1).Type = cdrCurveShape Then Set s = sr(1) ReDim action_arr(s.Curve.Nodes.Count + 1) ReDim controlpoints_arr(s.Curve.Nodes.Count + 1, 4) For lngNodeIndex_getting = 1 To s.Curve.Nodes.Count Set nodeThis = s.Curve.Nodes(lngNodeIndex_getting) If nodeThis.Type = cdrSymmetricalNode Then If Abs(Abs(nodeThis.Segment.EndingControlPointAngle - nodeThis.NextSegment.StartingControlPointAngle) - 180) > dblAngleTolerance Then action_arr(lngNodeIndex_getting) = "C" If nodeThis.Segment.Type = cdrCurveSegment Then controlpoints_arr(lngNodeIndex_getting, 1) = nodeThis.Segment.EndingControlPointX controlpoints_arr(lngNodeIndex_getting, 2) = nodeThis.Segment.EndingControlPointY End If If nodeThis.NextSegment.Type = cdrCurveSegment Then controlpoints_arr(lngNodeIndex_getting, 3) = nodeThis.NextSegment.StartingControlPointX controlpoints_arr(lngNodeIndex_getting, 4) = nodeThis.NextSegment.StartingControlPointY End If Else If Abs(nodeThis.Segment.EndingControlPointLength - nodeThis.NextSegment.StartingControlPointLength) > ActiveDocument.ToUnits(dblLengthToleranceTenthMicrons, cdrTenthMicron) Then action_arr(lngNodeIndex_getting) = "S" controlpoints_arr(lngNodeIndex_getting, 1) = nodeThis.Segment.EndingControlPointX controlpoints_arr(lngNodeIndex_getting, 2) = nodeThis.Segment.EndingControlPointY controlpoints_arr(lngNodeIndex_getting, 3) = nodeThis.NextSegment.StartingControlPointX controlpoints_arr(lngNodeIndex_getting, 4) = nodeThis.NextSegment.StartingControlPointY End If End If End If Next lngNodeIndex_getting For lngNodeIndex_setting = 1 To s.Curve.Nodes.Count Set nodeThis = s.Curve.Nodes(lngNodeIndex_setting) If action_arr(lngNodeIndex_setting) = "C" Then nodeThis.Type = cdrCuspNode If nodeThis.Segment.Type = cdrCurveSegment Then nodeThis.Segment.EndingControlPointX = controlpoints_arr(lngNodeIndex_setting, 1) nodeThis.Segment.EndingControlPointY = controlpoints_arr(lngNodeIndex_setting, 2) End If If nodeThis.NextSegment.Type = cdrCurveSegment Then nodeThis.NextSegment.StartingControlPointX = controlpoints_arr(lngNodeIndex_setting, 3) nodeThis.NextSegment.StartingControlPointY = controlpoints_arr(lngNodeIndex_setting, 4) End If lngNodesChangedToCuspCount = lngNodesChangedToCuspCount + 1 Else If action_arr(lngNodeIndex_setting) = "S" Then nodeThis.Type = cdrSmoothNode nodeThis.Segment.EndingControlPointX = controlpoints_arr(lngNodeIndex_setting, 1) nodeThis.Segment.EndingControlPointY = controlpoints_arr(lngNodeIndex_setting, 2) nodeThis.NextSegment.StartingControlPointX = controlpoints_arr(lngNodeIndex_setting, 3) nodeThis.NextSegment.StartingControlPointY = controlpoints_arr(lngNodeIndex_setting, 4) lngNodesChangedToSmoothCount = lngNodesChangedToSmoothCount + 1 End If End If Next lngNodeIndex_setting MsgBox "Number of nodes changed to Smooth: " & lngNodesChangedToSmoothCount & vbCrLf & vbCrLf & "Number of nodes changed to Cusp: " & lngNodesChangedToCuspCount, vbInformation, strMacroName Else MsgBox "Selection is not a Curve.", vbInformation, strMacroName End If Else MsgBox "Exactly one Curve shape must be selected.", vbInformation, strMacroName End If ExitSub: ActiveDocument.EndCommandGroup Optimization = False EventsEnabled = True Exit Sub ErrHandler: MsgBox "Error occured: " & Err.Description Resume ExitSub End Sub
Here is a new .GMS file:
JQ_Fix_Bogus_Symmetrical_Nodes _2018_07_03_0808.zip.
Here is a short video showing it working on consecutive bogus Symmetrical nodes. It's a simple but fairly dramatic example of how badly geometry can be distorted by these bogus nodes:
VIDEO: Fix Bogus Symmetrical Nodes 2.
Thing three: I realize now that one particular flavor of "bogus" Symmetrical node - one that is located at the end of a line segment (as opposed to Curve segment) - can generate an error with the code I posted earlier.
One of the tests I'm using to identify bogus symmetrical nodes - checking the lengths of the control points - is not valid for a Line segment. Note that this is "can", not "will", generate an error. It only gets to the "are the control point lengths equal?" test if it has already passed the "are the control point angles opposite in direction" test, and I don't think I ran into such a situation in my earlier testing.
Such a situation can occur, though so - a new version to take this possibility into account:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
Option Explicit Sub fix_bogus_symmetrical_nodes() Dim sr As ShapeRange Dim s As Shape Dim curveFixed As Curve Dim lngNodesChangedToCuspCount As Long Dim lngNodesChangedToSmoothCount As Long Const strMacroName As String = "Fix Bogus Symmetrical Nodes" On Error GoTo ErrHandler ActiveDocument.BeginCommandGroup "Fix Bogus Symmetrical Nodes" Set sr = ActiveSelectionRange If sr.Count = 1 Then If sr(1).Type = cdrCurveShape Then copy_curve_and_fix_bogus_symmetrical_nodes sr(1).Curve, curveFixed, lngNodesChangedToCuspCount, lngNodesChangedToSmoothCount sr(1).Curve.CopyAssign curveFixed MsgBox "Number of nodes changed to Smooth: " & lngNodesChangedToSmoothCount & vbCrLf & vbCrLf & "Number of nodes changed to Cusp: " & lngNodesChangedToCuspCount, vbInformation, strMacroName Else MsgBox "Selection is not a Curve.", vbInformation, strMacroName End If Else MsgBox "Exactly one Curve shape must be selected.", vbInformation, strMacroName End If ExitSub: ActiveDocument.EndCommandGroup Exit Sub ErrHandler: MsgBox "Error occured: " & Err.Description Resume ExitSub End Sub Function copy_curve_and_fix_bogus_symmetrical_nodes(ByVal SourceCurve As Curve, ByRef ResultCurve As Curve, Optional ByRef NumNodesChangedToCusp As Long, Optional ByRef NumNodesChangedToSmooth As Long) As Boolean Dim nodeThis As Node Const dblAngleTolerance As Double = 0.001 Const dblLengthToleranceTenthMicrons As Double = 50 Dim action_arr() As String Dim controlpoints_arr() As Double Dim lngNodeIndex_subpath_getting As Long Dim lngNodeIndex_setting As Long Dim subPathThis As SubPath On Error GoTo ErrHandler Set ResultCurve = SourceCurve.GetCopy ReDim action_arr(ResultCurve.Nodes.Count + 1) ReDim controlpoints_arr(ResultCurve.Nodes.Count + 1, 4) For Each subPathThis In ResultCurve.SubPaths For lngNodeIndex_subpath_getting = 1 To subPathThis.Nodes.Count Set nodeThis = subPathThis.Nodes(lngNodeIndex_subpath_getting) If nodeThis.Type = cdrSymmetricalNode Then If nodeThis.Segment.Type = cdrLineSegment Or nodeThis.NextSegment.Type = cdrLineSegment Or Abs(Abs(nodeThis.Segment.EndingControlPointAngle - nodeThis.NextSegment.StartingControlPointAngle) - 180) > dblAngleTolerance Then action_arr(nodeThis.AbsoluteIndex) = "C" If nodeThis.Segment.Type = cdrCurveSegment Then controlpoints_arr(nodeThis.AbsoluteIndex, 1) = nodeThis.Segment.EndingControlPointX controlpoints_arr(nodeThis.AbsoluteIndex, 2) = nodeThis.Segment.EndingControlPointY End If If nodeThis.NextSegment.Type = cdrCurveSegment Then controlpoints_arr(nodeThis.AbsoluteIndex, 3) = nodeThis.NextSegment.StartingControlPointX controlpoints_arr(nodeThis.AbsoluteIndex, 4) = nodeThis.NextSegment.StartingControlPointY End If Else If Abs(nodeThis.Segment.EndingControlPointLength - nodeThis.NextSegment.StartingControlPointLength) > ActiveDocument.ToUnits(dblLengthToleranceTenthMicrons, cdrTenthMicron) Then action_arr(nodeThis.AbsoluteIndex) = "S" controlpoints_arr(nodeThis.AbsoluteIndex, 1) = nodeThis.Segment.EndingControlPointX controlpoints_arr(nodeThis.AbsoluteIndex, 2) = nodeThis.Segment.EndingControlPointY controlpoints_arr(nodeThis.AbsoluteIndex, 3) = nodeThis.NextSegment.StartingControlPointX controlpoints_arr(nodeThis.AbsoluteIndex, 4) = nodeThis.NextSegment.StartingControlPointY End If End If End If Next lngNodeIndex_subpath_getting Next subPathThis For lngNodeIndex_setting = 1 To ResultCurve.Nodes.Count Set nodeThis = ResultCurve.Nodes(lngNodeIndex_setting) If action_arr(lngNodeIndex_setting) = "C" Then nodeThis.Type = cdrCuspNode If nodeThis.Segment.Type = cdrCurveSegment Then nodeThis.Segment.EndingControlPointX = controlpoints_arr(lngNodeIndex_setting, 1) nodeThis.Segment.EndingControlPointY = controlpoints_arr(lngNodeIndex_setting, 2) End If If nodeThis.NextSegment.Type = cdrCurveSegment Then nodeThis.NextSegment.StartingControlPointX = controlpoints_arr(lngNodeIndex_setting, 3) nodeThis.NextSegment.StartingControlPointY = controlpoints_arr(lngNodeIndex_setting, 4) End If NumNodesChangedToCusp = NumNodesChangedToCusp + 1 Else If action_arr(lngNodeIndex_setting) = "S" Then nodeThis.Type = cdrSmoothNode nodeThis.Segment.EndingControlPointX = controlpoints_arr(lngNodeIndex_setting, 1) nodeThis.Segment.EndingControlPointY = controlpoints_arr(lngNodeIndex_setting, 2) nodeThis.NextSegment.StartingControlPointX = controlpoints_arr(lngNodeIndex_setting, 3) nodeThis.NextSegment.StartingControlPointY = controlpoints_arr(lngNodeIndex_setting, 4) NumNodesChangedToSmooth = NumNodesChangedToSmooth + 1 End If End If Next lngNodeIndex_setting ExitFunc: Exit Function ErrHandler: MsgBox "Error occured: " & Err.Description Resume ExitFunc End Function
JQ_Fix_Bogus_Symmetrical_Nodes_2018_07_15_1836.
In addition to the small tweak to handle bogus symmetrical nodes on line segments, this latest version carries out the changes to the shape differently. Instead of making all changes directly to the Shape, it gets a copy of the Curve and does all of the work there. It only changes the Shape once, by applying the modified Curve information to it.
This way, CorelDRAW is not keeping track of many, many changes to the Shape. This is MUCH faster than the way I was doing it before, and CorelDRAW's use of memory does not increase nearly as much. After using the macro, if an Undo operation is performed, then that, too, is MUCH faster - because it is only undoing the one "update the Curve information" operation.
The improvement is obvious when working with a Shape that is significantly more complicated than the examples I showed earlier. This demonstration starts out with two identical copies of a Shape that was created by welding a lot of slightly-overlapping circular ellipses - and so has many bogus symmetrical nodes:
Fix Bogus Symmetrical Nodes - spirals
I'm just gob smacked by all this work, test/prove, rework, test/prove, rinse & repeat.
More than just being able to follow along with the thought, that you do this for the good of the community is more than humbling, gratifying and just plain makes my heart bubble.
Thank you. Mike
Thank you for the kind words, Mike!
I became aware of this problem back in November. I wondered at the time if there might be a way to fix the bogus nodes programmatically, but I had almost zero experience working with Curves in the API, and I didn't really try to engage it at that time. Some stuff I was working on recently had me working with Curves a little bit. I remembered this and thought, "maybe it's time to revisit that and take a closer look". The exercise that followed was educational for me, and some of what I learned has been put to good use in another macro that I've been working on.
The organization of the Community forum makes it practically impossible to discuss and share technical information in really effective ways. This thread is posted in the CorelDRAW 2018 forum. What about the 2017, X8, X7, X6, X5, X4, X3,... users who might benefit from reading it?
I have practically begged for the creation of a readily-visible, easily-approachable "Macros for Users" section of the forum specifically for discussion and sharing of macros, from the perspective of general users and do-it-yourself programmers. I think that there is a lot of missed opportunity there, but so far, no positive response from Corel - and I first brought this up with them nearly a year ago.
Sad! Discouraging!
When comparing the lengths of the control points to determine whether a node should be changed to Smooth, the code shown so far has been using an absolute "length tolerance". That is, if the two control points are the same length - within that tolerance - then the node is considered to still be symmetrical.
Since the length of the control points scales with the size of the Curve, that absolute tolerance would not be a "one size fits all" thing. I have changed that now so that the length tolerance is relative - a percentage of the length of the longer control point. So, instead of "are the lengths within 5 micrometers of each other?", it might be "are the lengths within 0.1% of each other?". I find that more intuitive to work with, too, in trying to think about how "non symmetrical" a node is.
Thing four: I have run into at least one case where shaping operations produced a symmetrical node that was on the end of an open curve! That type of situation would produce an error with my earlier code - again, where I was performing a test that isn't valid in that situation.
My code now checks for such a situation so as to handle it properly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
Option Explicit Sub fix_bogus_symmetrical_nodes() Dim sr As ShapeRange Dim s As Shape Dim curveFixed As Curve Dim lngNodesChangedToCuspCount As Long Dim lngNodesChangedToSmoothCount As Long Const dblCtrlPtAngleTolerance As Double = 0.05 Const dblCtrlPtLengthTolerancePercent As Double = 0.1 Const strMacroName As String = "Fix Bogus Symmetrical Nodes" On Error GoTo ErrHandler ActiveDocument.BeginCommandGroup "Fix Bogus Symmetrical Nodes" Set sr = ActiveSelectionRange If sr.Count = 1 Then If sr(1).Type = cdrCurveShape Then copy_curve_and_fix_bogus_symmetrical_nodes sr(1).Curve, curveFixed, dblCtrlPtAngleTolerance, dblCtrlPtLengthTolerancePercent, lngNodesChangedToCuspCount, lngNodesChangedToSmoothCount sr(1).Curve.CopyAssign curveFixed MsgBox "Number of nodes changed to Cusp: " & lngNodesChangedToCuspCount & vbCrLf & vbCrLf & "Number of nodes changed to Smooth: " & lngNodesChangedToSmoothCount, vbInformation, strMacroName Else MsgBox "Selection is not a Curve.", vbInformation, strMacroName End If Else MsgBox "Exactly one Curve shape must be selected.", vbInformation, strMacroName End If ExitSub: ActiveDocument.EndCommandGroup Exit Sub ErrHandler: MsgBox "Error occured: " & Err.Description Resume ExitSub End Sub Function copy_curve_and_fix_bogus_symmetrical_nodes(ByVal SourceCurve As Curve, ByRef ResultCurve As Curve, ByVal CPAngleTolerance As Double, ByVal CPLengthTolerancePercent As Double, Optional ByRef NumNodesChangedToCusp As Long, Optional ByRef NumNodesChangedToSmooth As Long) As Boolean Const strFunctionName = "copy_curve_and_fix_bogus_symmetrical_nodes()" Dim nodeThis As Node Dim action_arr() As String Dim controlpoints_arr() As Double Dim lngNodeIndex_subpath_getting As Long Dim lngNodeIndex_setting As Long Dim subPathThis As SubPath On Error GoTo ErrHandler Set ResultCurve = SourceCurve.GetCopy ReDim action_arr(ResultCurve.Nodes.Count + 1) ReDim controlpoints_arr(ResultCurve.Nodes.Count + 1, 4) For Each subPathThis In ResultCurve.SubPaths For lngNodeIndex_subpath_getting = 1 To subPathThis.Nodes.Count Set nodeThis = subPathThis.Nodes(lngNodeIndex_subpath_getting) If nodeThis.Type = cdrSymmetricalNode Then If Not subPathThis.Closed And nodeThis.Index = subPathThis.Nodes.Last.Index Then 'this is the last node of an open subpath action_arr(nodeThis.AbsoluteIndex) = "CL" If nodeThis.Segment.Type = cdrCurveSegment Then nodeThis.Segment.GetEndingControlPointPosition controlpoints_arr(nodeThis.AbsoluteIndex, 1), controlpoints_arr(nodeThis.AbsoluteIndex, 2) End If Else If Not subPathThis.Closed And nodeThis.Index = subPathThis.Nodes.First.Index Then 'this is the first node of an open subpath action_arr(nodeThis.AbsoluteIndex) = "CF" If nodeThis.NextSegment.Type = cdrCurveSegment Then nodeThis.NextSegment.GetStartingControlPointPosition controlpoints_arr(nodeThis.AbsoluteIndex, 3), controlpoints_arr(nodeThis.AbsoluteIndex, 4) End If Else 'this not the first or last node of an open subpath If nodeThis.Segment.Type = cdrLineSegment Or nodeThis.NextSegment.Type = cdrLineSegment Or Abs(Abs(nodeThis.Segment.EndingControlPointAngle - nodeThis.NextSegment.StartingControlPointAngle) - 180) > CPAngleTolerance Then action_arr(nodeThis.AbsoluteIndex) = "C" If nodeThis.Segment.Type = cdrCurveSegment Then nodeThis.Segment.GetEndingControlPointPosition controlpoints_arr(nodeThis.AbsoluteIndex, 1), controlpoints_arr(nodeThis.AbsoluteIndex, 2) End If If nodeThis.NextSegment.Type = cdrCurveSegment Then nodeThis.NextSegment.GetStartingControlPointPosition controlpoints_arr(nodeThis.AbsoluteIndex, 3), controlpoints_arr(nodeThis.AbsoluteIndex, 4) End If Else If length_difference_percent(nodeThis.Segment.EndingControlPointLength, nodeThis.NextSegment.StartingControlPointLength) > CPLengthTolerancePercent Then action_arr(nodeThis.AbsoluteIndex) = "S" nodeThis.Segment.GetEndingControlPointPosition controlpoints_arr(nodeThis.AbsoluteIndex, 1), controlpoints_arr(nodeThis.AbsoluteIndex, 2) nodeThis.NextSegment.GetStartingControlPointPosition controlpoints_arr(nodeThis.AbsoluteIndex, 3), controlpoints_arr(nodeThis.AbsoluteIndex, 4) End If End If End If End If End If Next lngNodeIndex_subpath_getting Next subPathThis For lngNodeIndex_setting = 1 To ResultCurve.Nodes.Count Set nodeThis = ResultCurve.Nodes(lngNodeIndex_setting) Select Case action_arr(lngNodeIndex_setting) Case "CL" 'this is the last node of an open subpath nodeThis.Type = cdrCuspNode If nodeThis.Segment.Type = cdrCurveSegment Then nodeThis.Segment.SetEndingControlPointPosition controlpoints_arr(nodeThis.AbsoluteIndex, 1), controlpoints_arr(nodeThis.AbsoluteIndex, 2) End If NumNodesChangedToCusp = NumNodesChangedToCusp + 1 Case "CF" 'this is the first node of an open subpath nodeThis.Type = cdrCuspNode If nodeThis.NextSegment.Type = cdrCurveSegment Then nodeThis.NextSegment.SetStartingControlPointPosition controlpoints_arr(nodeThis.AbsoluteIndex, 3), controlpoints_arr(nodeThis.AbsoluteIndex, 4) End If NumNodesChangedToCusp = NumNodesChangedToCusp + 1 Case "C" 'this not the first or last node of an open subpath nodeThis.Type = cdrCuspNode If nodeThis.Segment.Type = cdrCurveSegment Then nodeThis.Segment.SetEndingControlPointPosition controlpoints_arr(lngNodeIndex_setting, 1), controlpoints_arr(lngNodeIndex_setting, 2) End If If nodeThis.NextSegment.Type = cdrCurveSegment Then nodeThis.NextSegment.SetStartingControlPointPosition controlpoints_arr(lngNodeIndex_setting, 3), controlpoints_arr(lngNodeIndex_setting, 4) End If NumNodesChangedToCusp = NumNodesChangedToCusp + 1 Case "S" 'this not the first or last node of an open subpath nodeThis.Type = cdrSmoothNode nodeThis.Segment.SetEndingControlPointPosition controlpoints_arr(lngNodeIndex_setting, 1), controlpoints_arr(lngNodeIndex_setting, 2) nodeThis.NextSegment.SetStartingControlPointPosition controlpoints_arr(lngNodeIndex_setting, 3), controlpoints_arr(lngNodeIndex_setting, 4) NumNodesChangedToSmooth = NumNodesChangedToSmooth + 1 End Select Next lngNodeIndex_setting ExitFunc: Exit Function ErrHandler: MsgBox "Error occured: " & Err.Description & vbCrLf & vbCrLf & strFunctionName, vbExclamation Resume ExitFunc End Function Function length_difference_percent(ByVal length_1 As Double, ByVal length_2 As Double) As Double Const strFunctionName = "length_difference_percent()" On Error GoTo ErrHandler If Not (length_1 < 0 Or length_2 < 0) Then If length_1 = length_2 Then length_difference_percent = 0 Else If length_1 > length_2 Then length_difference_percent = (length_1 - length_2) / length_1 * 100 Else length_difference_percent = (length_2 - length_1) / length_2 * 100 End If End If Else MsgBox "One or both lengths are less than zero." & vbCrLf & vbCrLf & strFunctionName, vbExclamation length_difference_percent = -1 End If ExitFunc: Exit Function ErrHandler: MsgBox "Error occurred: " & Err.Description & vbCrLf & vbCrLf & strFunctionName, vbExclamation Resume ExitFunc End Function
No new .GMS file this time, as I've also been working on putting that code to use in a more flexible, more user-friendly package:
I think it's getting pretty close.