-
0
2
2
-
1
0
7
- 1c961c8b-9745-4a92-a43d-080de1ead765
- Shaded
- 1
-
100;150;0;0
-
100;0;150;0
- 635273898765795129
- elastica_curve_examples - Copy.ghx
- 0
-
-102
40
- 1
- 0
- 0
- 149
- c552a431-af5b-46a9-a8a4-0fcbc27ef596
- Group
- 1
-
150;170;135;255
- A group of Grasshopper objects
- d013dc08-a8cd-4383-aa4a-7e9f0b202f67
- 19d4e5e6-a3fb-4e4d-b426-93c0b41f974c
- ce2f14ec-483c-4899-a8cb-784a62168957
- b2a67d0f-c66e-46a9-8efd-f7442d233d5d
- 32bb1a9f-9575-4b8c-8a60-a65a7b9dd15f
- 98102773-859e-4cf3-83a5-41f68379af66
- d68f5884-1ed1-4bd5-ab64-b7040370d59b
- 8cd6ad76-7f71-4948-8c5e-9a3e2549985f
- d53a1087-053a-44d5-b485-68a8b5d09ce4
- cc8dfb80-5022-4b13-83c9-a787888900e8
- 072c5f2f-5efd-4587-8eb9-f4eacb6f59a9
- 25d0b3b4-fc42-4433-a4bf-e70bfa828143
- 5137ef09-783f-4981-a9ec-aa4f2fc8e019
- 225afdb2-480f-435b-a1cb-84170b3afd2f
- 20228f31-e357-4d65-8747-46e12348391c
- 7c2a1ac2-4916-4aa3-9b0a-566a67f36e60
- 95f9fd7f-37dc-4bd8-8105-7301ef052bdd
- 17
- 07a70634-4e1a-4226-b5d3-17b0a4e0f460
- Group
- 079bd9bd-54a0-41d4-98af-db999015f63d
- VB Script
- Private Function IsSet(ByVal param As String) As Boolean ' Check if an input parameter has data
Dim i As Integer = Component.Params.IndexOfInputParam(param)
If i > -1 Then
Return Component.Params.Input.ElementAt(i).DataType > 1 ' input parameter DataType of 1 means it's not receiving input (internal or external)
Else
Msg("error", "Input parameter '" & param & "' not found")
Return False
End If
End Function
Private Sub Msg(ByVal type As String, ByVal msg As String) ' Output an error, warning, or informational message
Select Case type
Case "error"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, msg)
Print("Error: " & msg)
Case "warning"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, msg)
Print("Warning: " & msg)
Case "info"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, msg)
Print(msg)
End Select
End Sub
' Solve for the m parameter from length and width (reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m))
Private Function SolveMFromLenWid(ByVal L As Double, ByVal w As Double) As Double
If w = 0 Then
Return Defined.M_ZERO_W ' for the boundry condition width = 0, bypass the function and return the known m value
End If
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwl As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwl = 2 * EllipticE(m) / EllipticK(m) - 1 ' calculate w/L with the test value of m
If cwl < w / L Then ' compares the calculated w/L with the actual w/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Solve for the m parameter from length and height (reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m))
' Note that it's actually possible to find 2 valid values for m (hence 2 width values) at certain height values
Private Function SolveMFromLenHt(ByVal L As Double, ByVal h As Double) As List(Of Double)
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim twoWidths As Boolean = h / L >= Defined.DOUBLE_W_HL_RATIO And h / L < Defined.MAX_HL_RATIO ' check to see if h/L is within the range where 2 solutions for the width are possible
Dim m As Double
Dim mult_m As New List(Of Double)
Dim chl As Double
If twoWidths Then
' find the first of two possible solutions for m with the following limits:
lower = Defined.M_DOUBLE_W ' see constants at bottom of script
upper = Defined.M_MAXHEIGHT ' see constants at bottom of script
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
' then find the second of two possible solutions for m with the following limits:
lower = Defined.M_MAXHEIGHT ' see constants at bottom of script
upper = 1
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl < h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
If m <= Defined.M_MAX Then ' return this m parameter only if it falls within the maximum useful value (above which the curve breaks down)
mult_m.Add(m)
End If
Else
' find the one possible solution for the m parameter
upper = Defined.M_DOUBLE_W ' limit the upper end of the search to the maximum value of m for which only one solution exists
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
End If
Return mult_m
End Function
' Solve for the m parameter from width and height (derived from reference {1} equations (33) and (34) with same notes as above)
Private Function SolveMFromWidHt(ByVal w As Double, ByVal h As Double) As Double
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwh As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwh = (2 * EllipticE(m) - EllipticK(m)) / Math.Sqrt(m) ' calculate w/h with the test value of m
If cwh < w / h Then ' compares the calculated w/h with the actual w/h then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Calculate length based on height and an m parameter, derived from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_L(ByVal h As Double, ByVal m As Double) As Double
Return h * EllipticK(m) / Math.Sqrt(m)
End Function
' Calculate width based on length and an m parameter, derived from reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m)
Private Function Cal_W(ByVal L As Double, ByVal m As Double) As Double
Return L * (2 * EllipticE(m) / EllipticK(m) - 1)
End Function
' Calculate height based on length and an m parameter, from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_H(ByVal L As Double, ByVal m As Double) As Double
Return L * Math.Sqrt(m) / EllipticK(m)
End Function
' Calculate the unique m parameter based on a start tangent angle, from reference {2}, just above equation (9a), that states k = Sin(angle / 2 + Pi / 4),
' but as m = k^2 and due to this script's need for an angle rotated 90° versus the one in reference {1}, the following formula is the result
' New note: verified by reference {4}, pg. 78 at the bottom
Private Function Cal_M(ByVal a As Double) As Double
Return (1 - Math.Cos(a)) / 2 ' equal to Sin^2(a/2) too
End Function
' Calculate start tangent angle based on an m parameter, derived from above formula
Private Function Cal_A(ByVal m As Double) As Double
Return Math.Acos(1 - 2 * m)
End Function
' This is the heart of this script, taking the found (or specified) length, width, and angle values along with the found m parameter to create
' a list of points that approximate the shape or form of the elastica. It works by finding the x and y coordinates (which are reversed versus
' the original equations (12a) and (12b) from reference {2} due to the 90° difference in orientation) based on the tangent angle along the curve.
' See reference {2} for more details on how they derived it. Note that to simplify things, the algorithm only calculates the points for half of the
' curve, then mirrors those points along the y-axis.
Private Function FindBendForm(ByVal L As Double, ByVal w As Double, ByVal m As Double, ByVal ang As Double, ByVal refPln As Plane) As List(Of Point3d)
L = L / 2 ' because the below algorithm is based on the formulas in reference {2} for only half of the curve
w = w / 2 ' same
If ang = 0 Then ' if angle (and height) = 0, then simply return the start and end points of the straight line
Dim out As New List(Of Point3d)
out.Add(refPln.PointAt(w, 0, 0))
out.Add(refPln.PointAt(-w, 0, 0))
Return out
End If
Dim x As Double
Dim y As Double
Dim halfCurvePts As New List(Of Point3d)
Dim fullCurvePts As New List(Of Point3d)
Dim translatedPts As New List(Of Point3d)
ang -= Math.PI / 2 ' a hack to allow this algorithm to work, since the original curve in paper {2} was rotated 90°
Dim angB As Double = ang + (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' angB is the 'lowercase theta' which should be in formula {2}(12b) as the interval
' start [a typo...see equation(3)]. It's necessary to start angB at ang + [interval] instead of just ang due to integration failing at angB = ang
halfCurvePts.Add(New Point3d(w, 0, 0)) ' start with this known initial point, as integration will fail when angB = ang
' each point {x, y} is calculated from the tangent angle, angB, that occurs at each point (which is why this iterates from ~ang to -pi/2, the known end condition)
Do While Math.Round(angB, Defined.ROUNDTO) >= Math.Round(-Math.PI / 2, Defined.ROUNDTO)
y = (Math.Sqrt(2) * Math.Sqrt(Math.Sin(ang) - Math.Sin(angB)) * (w + L)) / (2 * EllipticE(m)) ' note that x and y are swapped vs. (12a) and (12b)
x = (L / (Math.Sqrt(2) * EllipticK(m))) * Simpson(angB, -Math.PI / 2, 500, ang) ' calculate the Simpson approximation of the integral (function f below)
' over the interval angB ('lowercase theta') to -pi/2. side note: is 500 too few iterations for the Simson algorithm?
If Math.Round(x, Defined.ROUNDTO) = 0 Then x = 0
halfCurvePts.Add(New Point3d(x, y, 0))
angB += (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' onto the next tangent angle
Loop
' After finding the x and y values for half of the curve, add the {-x, y} values for the rest of the curve
For Each point As Point3d In halfCurvePts
If Math.Round(point.X, Defined.ROUNDTO) = 0 Then
If Math.Round(point.Y, Defined.ROUNDTO) = 0 Then
fullCurvePts.Add(New Point3d(0, 0, 0)) ' special case when width = 0: when x = 0, only duplicate the point when y = 0 too
End If
Else
fullCurvePts.Add(New Point3d(-point.X, point.Y, 0))
End If
Next
halfCurvePts.Reverse
fullCurvePts.AddRange(halfCurvePts)
For Each p As Point3d In fullCurvePts
translatedPts.Add(refPln.PointAt(p.X, p.Y, p.Z)) ' translate the points from the reference plane to the world plane
Next
Return translatedPts
End Function
' Interpolates the points from FindBendForm to create the Elastica curve. Uses start & end tangents for greater accuracy.
Private Function MakeCurve(ByVal pts As List(Of Point3d), ByVal ang As Double, ByVal refPln As Plane) As Curve
If ang <> 0 Then
Dim ts, te As New Vector3d(refPln.XAxis)
ts.Rotate(ang, refPln.ZAxis)
te.Rotate(-ang, refPln.ZAxis)
Return Curve.CreateInterpolatedCurve(pts, 3, CurveKnotStyle.Chord, ts, te) ' 3rd degree curve with 'Chord' Knot Style
Else
Return Curve.CreateInterpolatedCurve(pts, 3) ' if angle (and height) = 0, then simply interpolate the straight line (no start/end tangents)
End If
End Function
' Implements the Simpson approximation for an integral of function f below
Public Function Simpson(a As Double, b As Double, n As Integer, theta As Double) As Double 'n should be an even number
Dim j As Integer, s1 As Double, s2 As Double, h As Double
h = (b - a) / n
s1 = 0
s2 = 0
For j = 1 To n - 1 Step 2
s1 = s1 + fn(a + j * h, theta)
Next j
For j = 2 To n - 2 Step 2
s2 = s2 + fn(a + j * h, theta)
Next j
Simpson = h / 3 * (fn(a, theta) + 4 * s1 + 2 * s2 + fn(b, theta))
End Function
' Specific calculation for the above integration
Public Function fn(x As Double, theta As Double) As Double
fn = Math.Sin(x) / (Math.Sqrt(Math.Sin(theta) - Math.Sin(x))) ' from reference {2} formula (12b)
End Function
' Return the Complete Elliptic integral of the 1st kind
' Abramowitz and Stegun p.591, formula 17.3.11
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticK(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum += Math.Pow(m, i) * Math.Pow(term, 2)
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
' Return the Complete Elliptic integral of the 2nd kind
' Abramowitz and Stegun p.591, formula 17.3.12
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticE(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum -= Math.Pow(m, i) * Math.Pow(term, 2) / above
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
Friend Partial NotInheritable Class Defined
Private Sub New()
End Sub
' Note: most of these values for m and h/L ratio were found with Wolfram Alpha and either specific intercepts (x=0) or local minima/maxima. They should be constant.
Public Const M_SKETCHY As Double = 0.95 ' value of the m parameter where the curvature near the ends of the curve gets wonky
Public Const M_MAX As Double = 0.993 ' maximum useful value of the m parameter, above which this algorithm for the form of the curve breaks down
Public Const M_ZERO_W As Double = 0.826114765984970336 ' value of the m parameter when width = 0
Public Const M_MAXHEIGHT As Double = 0.701327460663101223 ' value of the m parameter at maximum possible height of the bent rod/wire
Public Const M_DOUBLE_W As Double = 0.180254422335013983 ' minimum value of the m parameter when two width values are possible for a given height and length
Public Const DOUBLE_W_HL_RATIO As Double = 0.257342117984635757 ' value of the height/length ratio above which there are two possible width values
Public Const MAX_HL_RATIO As Double = 0.403140189705650243 ' maximum possible value of the height/length ratio
Public Const MAXERR As Double = 0.0000000001 ' error tolerance
Public Const MAXIT As Integer = 100 ' maximum number of iterations
Public Const ROUNDTO As Integer = 10 ' number of decimal places to round off to
Public Const CURVEDIVS As Integer = 50 ' number of sample points for building the curve (or half-curve as it were)
End Class
- A VB.NET scriptable component
-
98
86
- true
- d013dc08-a8cd-4383-aa4a-7e9f0b202f67
- VB Script
- VB
- true
- 0
- ' -----------------------------------------------------------------
' Elastic Bending Script by Will McElwain
' Created February 2014
'
' DESCRIPTION:
' This beast creates the so-called 'elastica curve', the shape a long, thin rod or wire makes when it is bent elastically (i.e. not permanently). In this case, force
' is assumed to only be applied horizontally (which would be in line with the rod at rest) and both ends are assumed to be pinned or hinged meaning they are free
' to rotate (as opposed to clamped, when the end tangent angle is fixed, usually horizontally). An interesting finding is that it doesn't matter what the material or
' cross-sectional area is, as long as they're uniform along the entire length. Everything makes the same shape when bent as long as it doesn't cross the threshold
' from elastic to plastic (permanent) deformation (I don't bother to find that limit here, but can be found if the yield stress for a material is known).
'
' Key to the formulas used in this script are elliptic integrals, specifically K(m), the complete elliptic integral of the first kind, and E(m), the complete elliptic
' integral of the second kind. There was a lot of confusion over the 'm' and 'k' parameters for these functions, as some people use them interchangeably, but they are
' not the same. m = k^2 (thus k = Sqrt(m)). I try to use the 'm' parameter exclusively to avoid this confusion. Note that there is a unique 'm' parameter for every
' configuration/shape of the elastica curve.
'
' This script tries to find that unique 'm' parameter based on the inputs. The algorithm starts with a test version of m, evaluates an expression, say 2*E(m)/K(m)-1,
' then compares the result to what it should be (in this case, a known width/length ratio). Iterate until the correct m is found. Once we have m, we can then calculate
' all of the other unknowns, then find points that lie on that curve, then interpolate those points for the actual curve. You can also use Wolfram|Alpha as I did to
' find the m parameter based on the equations in this script (example here: http://tiny.cc/t4tpbx for when say width=45.2 and length=67.1).
'
' Other notes:
' * This script works with negative values for width, which will creat a self-intersecting curve (as it should). The curvature of the elastica starts to break down around
' m=0.95 (~154°), but this script will continue to work until M_MAX, m=0.993 (~169°). If you wish to ignore self-intersecting curves, set ignoreSelfIntersecting to True
' * When the only known values are length and height, it is actually possible for certain ratios of height to length to have two valid m values (thus 2 possible widths
' and angles). This script will return them both.
' * Only the first two valid parameters (of the required ones) will be used, meaning if all four are connected (length, width or a PtB, height, and angle), this script will
' only use length and width (or a PtB).
' * Depending on the magnitude of your inputs (say if they're really small, like if length < 10), you might have to increase the constant ROUNDTO at the bottom
'
' REFERENCES:
' {1} "The elastic rod" by M.E. Pacheco Q. & E. Pina, http://www.scielo.org.mx/pdf/rmfe/v53n2/v53n2a8.pdf
' {2} "An experiment in nonlinear beam theory" by A. Valiente, http://www.deepdyve.com/lp/doc/I3lwnxdfGz , also here: http://tiny.cc/Valiente_AEiNBT
' {3} "Snap buckling, writhing and Loop formation In twisted rods" by V.G.A. GOSS, http://myweb.lsbu.ac.uk/~gossga/thesisFinal.pdf
' {4} "Theory of Elastic Stability" by Stephen Timoshenko, http://www.scribd.com/doc/50402462/Timoshenko-Theory-of-Elastic-Stability (start on p. 76)
'
' INPUT:
' PtA - First anchor point (required)
' PtB - Second anchor point (optional, though 2 out of the 4--length, width, height, angle--need to be specified)
' [note that PtB can be the same as PtA (meaning width would be zero)]
' [also note that if a different width is additionally specified that's not equal to the distance between PtA and PtB, then the end point will not equal PtB anymore]
' Pln - Plane of the bent rod/wire, which bends up in the +y direction. The line between PtA and PtB (if specified) must be parallel to the x-axis of this plane
'
' ** 2 of the following 4 need to be specified **
' Len - Length of the rod/wire, which needs to be > 0
' Wid - Width between the endpoints of the curve [note: if PtB is specified in addition, and distance between PtA and PtB <> width, the end point will be relocated
' Ht - Height of the bent rod/wire (when negative, curve will bend downward, relative to the input plane, instead)
' Ang - Inner departure angle or tangent angle (in radians) at the ends of the bent rod/wire. Set up so as width approaches length (thus height approaches zero), angle approaches zero
'
' * Following variables only needed for optional calculating of bending force, not for shape of curve.
' E - Young's modulus (modulus of elasticity) in GPa (=N/m^2) (material-specific. for example, 7075 aluminum is roughly 71.7 GPa)
' I - Second moment of area (or area moment of inertia) in m^4 (cross-section-specific. for example, a hollow rod
' would have I = pi * (outer_diameter^4 - inner_diameter^4) / 32
' Note: E*I is also known as flexural rigidity or bending stiffness
'
' OUTPUT:
' out - only for debugging messages
' Pts - the list of points that approximate the shape of the elastica
' Crv - the 3rd-degree curve interpolated from those points (with accurate start & end tangents)
' L - the length of the rod/wire
' W - the distance (width) between the endpoints of the rod/wire
' H - the height of the bent rod/wire
' A - the tangent angle at the (start) end of the rod/wire
' F - the force needed to hold the rod/wire in a specific shape (based on the material properties & cross-section) **be sure your units for 'I' match your units for the
' rest of your inputs (length, width, etc.). Also note that the critical buckling load (force) that makes the rod/wire start to bend can be found at height=0
'
' THANKS TO:
' Mårten Nettelbladt (thegeometryofbending.blogspot.com)
' Daniel Piker (Kangaroo plugin)
' David Rutten (Grasshopper guru)
' Euler & Bernoulli (the O.G.'s)
'
' -----------------------------------------------------------------
Dim ignoreSelfIntersecting As Boolean = False ' set to True if you don't want to output curves where width < 0, which creates a self-intersecting curve
Dim inCt As Integer = 0 ' count the number of required parameters that are receiving data
Dim length As Double
Dim width As System.Object = Nothing ' need to set as Nothing so we can check if it has been assigned a value later
Dim height As Double
Dim angle As Double
Dim m As Double
Dim multiple_m As New List(Of Double)
Dim AtoB As Line
Dim flip_H As Boolean = False ' if height is negative, this flag will be set
Dim flip_A As Boolean = False ' if angle is negative, this flag will be set
If Not IsSet("Pln") Then
Msg("error", "Base plane is not set")
Return
End If
If Not IsSet("PtA") Then
Msg("error", "Point A is not set")
Return
End If
If Math.Round(Pln.DistanceTo(PtA), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point A is not on the base plane")
Return
End If
Dim refPlane As Plane = Pln ' create a reference plane = input plane and set the origin of it to PtA in case PtA isn't the origin already
refPlane.Origin = PtA
If IsSet("PtB") Then
If Math.Round(Pln.DistanceTo(PtB), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point B is not on the base plane")
Return
End If
AtoB = New Line(PtA, PtB)
If AtoB.Length <> 0 And Not AtoB.Direction.IsPerpendicularTo(Pln.YAxis) Then
Msg("error", "The line between PtA and PtB is not perpendicular to the Y-axis of the specified plane")
Return
End If
inCt += 1
If IsSet("Wid") Then Msg("info", "Wid will override the distance between PtA and PtB. If you do not want this to happen, disconnect PtB or Wid.")
width = PtA.DistanceTo(PtB) ' get the width (distance) between PtA and PtB
Dim refPtB As Point3d
refPlane.RemapToPlaneSpace(PtB, refPtB)
If refPtB.X < 0 Then width = -width ' check if PtB is to the left of PtA...if so, width is negative
End If
If IsSet("Len") Then inCt += 1
If IsSet("Wid") Then inCt += 1
If IsSet("Ht") Then inCt += 1
If IsSet("Ang") Then inCt += 1
If inCt > 2 Then Msg("info", "More parameters set than are required (out of length, width, height, angle). Only using the first two valid ones.")
' check for connected/specified inputs. note: only the first two that it comes across will be used
If IsSet("Len") Then ' if length is specified then...
If Len <= 0 Then
Msg("error", "Length cannot be negative or zero")
Return
End If
If IsSet("Wid") Then ' find height & angle based on length and specified width
If Wid > Len Then
Msg("error", "Width is greater than length")
Return
End If
If Wid = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
width = Wid
Else
m = SolveMFromLenWid(Len, Wid)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
width = Wid
End If
Else If width IsNot Nothing Then ' find height & angle based on length and calculated width (distance between PtA and PtB)
If width > Len Then
Msg("error", "Width is greater than length")
Return
End If
If width = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
Else
m = SolveMFromLenWid(Len, width)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
Else If IsSet("Ht") Then ' find width & angle based on length and height ** possible to return 2 results **
If Math.Abs(Ht / Len) > Defined.MAX_HL_RATIO Then
Msg("error", "Height not possible with given length")
Return
End If
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
width = Len
angle = 0
Else
multiple_m = SolveMFromLenHt(Len, Ht) ' note that it's possible for two values of m to be found if height is close to max height
If multiple_m.Count = 1 Then ' if there's only one m value returned, calculate the width & angle here. we'll deal with multiple m values later
m = multiple_m.Item(0)
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
End If
height = Ht
Else If IsSet("Ang") Then ' find width & height based on length and angle
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
width = Len
height = 0
Else
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to length")
Return
End If
length = Len
Else If IsSet("Wid") Then ' if width is specified then...
If IsSet("Ht") Then ' find length & angle based on specified width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = Wid
angle = 0
Else
m = SolveMFromWidHt(Wid, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on specified width and angle
If Wid = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = Wid
height = 0
Else
length = Wid / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to width (Wid)")
Return
End If
width = Wid
Else If width IsNot Nothing Then ' if width is determined by PtA and PtB then...
If IsSet("Ht") Then ' find length & angle based on calculated width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = width
angle = 0
Else
m = SolveMFromWidHt(width, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on calculated width and angle
If width = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = width
height = 0
Else
length = width / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to PtA and PtB")
Return
End If
Else If IsSet("Ht") Then ' if height is specified then...
If IsSet("Ang") Then ' find length & width based on height and angle
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_H = True
flip_A = True
End If
If Ht = 0 Then
Msg("error", "Height can't = 0 if only height and angle are specified")
Return
Else
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = Not flip_A
flip_H = Not flip_H
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then
Msg("error", "Angle can't = 0 if only height and angle are specified")
Return
Else
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
width = Cal_W(length, m) ' L * (2 * E(m) / K(m) - 1)
End If
angle = Ang
End If
height = Ht
Else
Msg("error", "Need to specify one more parameter in addition to height")
Return
End If
Else If IsSet("Ang") Then
Msg("error", "Need to specify one more parameter in addition to angle")
Return
Else
Msg("error", "Need to specify two of the four parameters: length, width (or PtB), height, and angle")
Return
End If
If m > Defined.M_MAX Then
Msg("error", "Form of curve not solvable with current algorithm and given inputs")
Return
End If
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
If multiple_m.Count > 1 Then ' if there is more than one m value returned, calculate the width, angle, and curve for each
Dim multi_pts As New DataTree(Of Point3d)
Dim multi_crv As New List(Of Curve)
Dim tmp_pts As New List(Of Point3d)
Dim multi_W, multi_A, multi_F As New List(Of Double)
Dim j As Integer = 0 ' used for creating a new branch (GH_Path) for storing pts which is itself a list of points
For Each m_val As Double In multiple_m
width = Cal_W(length, m_val) 'length * (2 * EllipticE(m_val) / EllipticK(m_val) - 1)
If width < 0 And ignoreSelfIntersecting Then
Msg("warning", "One curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Continue For
End If
If m_val >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve whose width = " & Math.Round(width, 4) & " is not guaranteed")
angle = Cal_A(m_val) 'Math.Asin(2 * m_val - 1)
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
tmp_pts = FindBendForm(length, width, m_val, angle, refPlane)
multi_pts.AddRange(tmp_pts, New GH_Path(j))
multi_crv.Add(MakeCurve(tmp_pts, angle, refPlane))
multi_W.Add(width)
If flip_A Then angle = -angle
multi_A.Add(angle)
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
multi_F.Add(EllipticK(m_val) ^ 2 * E * I / length ^ 2) ' from reference {4} pg. 79
j += 1
refPlane.Origin = PtA ' reset the reference plane origin to PtA for the next m_val
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m_val & ", k=" & Math.Sqrt(m_val) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
Next
' assign the outputs
Pts = multi_pts
Crv = multi_crv
L = length
W = multi_W
If flip_H Then height = -height
H = height
A = multi_A
F = multi_F
Else ' only deal with the single m value
If m >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve at these parameters is not guaranteed")
If width < 0 And ignoreSelfIntersecting Then
Msg("error", "Curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Return
End If
Pts = FindBendForm(length, width, m, angle, refPlane)
Crv = MakeCurve(pts, angle, refPlane)
L = length
W = width
If flip_H Then height = -height
H = height
If flip_A Then angle = -angle
A = angle
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
F = EllipticK(m) ^ 2 * E * I / length ^ 2 ' from reference {4} pg. 79. Note: the critical buckling (that makes the rod/wire start to bend) can be found at height=0 (width=length)
'height = Math.Sqrt(((2 * Len / 5) ^ 2 - ((Wid - Len / 5) / 2) ^ 2) ' quick approximation discovered by Mårten of 'Geometry of Bending' fame ( http://tiny.cc/it2pbx )
'width = (Len +/- 2 * Math.Sqrt(4 * Len ^ 2 - 25 * Ht ^ 2)) / 5 ' derived from above
'length = (2 * Math.Sqrt(15 * Ht ^ 2 + 4 * Wid ^ 2) - Wid) / 3 ' derived from above
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m & ", k=" & Math.Sqrt(m) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
End If
-
612
233
84
184
-
654
325
- 9
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 8
- 3ede854e-c753-40eb-84cb-b48008f14fd4
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- true
- Script Variable PtA
- 920df659-6d29-453d-9295-577245828ba6
- PtA
- PtA
- true
- 0
- true
- 7451bc70-5fc3-43a3-bb48-ff10952414e7
- 1
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
614
235
25
20
-
628
245
- true
- Script Variable PtB
- eeb8ccaa-8966-4eab-8949-3eb384a12d84
- PtB
- PtB
- true
- 0
- true
- d5104343-e872-4369-9a14-a75a852c1a15
- 1
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
614
255
25
20
-
628
265
- true
- Script Variable Pln
- ee4f4d3f-f195-437b-88af-35d3a73d66ad
- Pln
- Pln
- true
- 0
- true
- df7d1e6a-049f-4594-9fb2-7dda33d26e57
- 1
- 3897522d-58e9-4d60-b38c-978ddacfedd8
-
614
275
25
20
-
628
285
- true
- Script Variable Len
- 999531d8-8fc7-4421-8afb-076eb4ce3f6e
- Len
- Len
- true
- 0
- true
- ce2f14ec-483c-4899-a8cb-784a62168957
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
614
295
25
20
-
628
305
- true
- Script Variable Wid
- 8aba3acb-d87c-46a0-aef3-179156140406
- Wid
- Wid
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
614
315
25
20
-
628
325
- true
- Script Variable Ht
- 54082c0a-ad9c-49e6-97c2-34b9d8c0e605
- Ht
- Ht
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
614
335
25
20
-
628
345
- true
- Script Variable Ang
- 998111e9-4c7d-4b27-88a9-01982081691a
- Ang
- Ang
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
614
355
25
20
-
628
365
- true
- Script Variable E
- b0ed1e4b-bad1-4910-9cd3-3178fc1a708a
- E
- E
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
614
375
25
20
-
628
385
- true
- Script Variable I
- 8058a335-90ef-4152-920c-88e68de69acc
- I
- I
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
614
395
25
20
-
628
405
- 1
- Print, Reflect and Error streams
- 17655ef3-6a9d-43b9-a699-bb23d2e2baff
- out
- out
- false
- 0
-
669
235
25
22
-
681.5
246.25
- Output parameter Pts
- d4f9a77d-b3a2-46c6-91de-6ce275666f2d
- Pts
- Pts
- false
- 0
-
669
257
25
23
-
681.5
268.75
- Output parameter Crv
- 1b8d948b-eedb-4c3c-bfba-ceaee74ff110
- Crv
- Crv
- false
- 0
-
669
280
25
22
-
681.5
291.25
- Output parameter L
- 0d6fe24b-f96e-4e86-bad3-d29ae034394e
- L
- L
- false
- 0
-
669
302
25
23
-
681.5
313.75
- Output parameter W
- 816f49f4-39a6-4705-80c7-e2a924ac1e0c
- W
- W
- false
- 0
-
669
325
25
22
-
681.5
336.25
- Output parameter H
- b00909dc-b385-4e3e-a3a8-9e76efdaadeb
- H
- H
- false
- 0
-
669
347
25
23
-
681.5
358.75
- Output parameter A
- 9632d9b7-ad5c-4b42-bc41-5bf9a4af0115
- A
- A
- false
- 0
-
669
370
25
22
-
681.5
381.25
- Output parameter F
- 28c91c87-29e8-4bc8-a5ff-18aadc6f0ecd
- F
- F
- false
- 0
-
669
392
25
23
-
681.5
403.75
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 19d4e5e6-a3fb-4e4d-b426-93c0b41f974c
- Number Slider
- width
- false
- 0
-
158
312
384
20
-
158.3465
312.3785
- 2
- 1
- 0
- 400
- -130
- 0
- 183.21
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- ce2f14ec-483c-4899-a8cb-784a62168957
- Number Slider
- length
- false
- 0
-
158
285
385
20
-
158.0028
285.5286
- 2
- 1
- 0
- 400
- 0
- 0
- 300
- fbac3e32-f100-4292-8692-77240a42fd1a
- Point
- Contains a collection of three-dimensional points
- true
- b2a67d0f-c66e-46a9-8efd-f7442d233d5d
- Point
- Pt
- false
- d4f9a77d-b3a2-46c6-91de-6ce275666f2d
- 1
-
782
194
50
24
-
807.4574
206.2478
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 32bb1a9f-9575-4b8c-8a60-a65a7b9dd15f
- Panel
- false
- 0
- 2296b093-286c-438d-aa59-465d23147f1c
- 1
- Double click to edit panel content…
-
855
408
105
55
- 0
- 0
- 0
-
855.6731
408.6088
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 0d77c51e-584f-44e8-aed2-c2ddf4803888
- Degrees
- Convert an angle specified in radians to degrees
- 98102773-859e-4cf3-83a5-41f68379af66
- Degrees
- Deg
-
754
421
64
28
-
784
435
- Angle in radians
- f013de98-8461-42d6-94e2-d4f473814c3f
- Radians
- R
- false
- 9632d9b7-ad5c-4b42-bc41-5bf9a4af0115
- 1
-
756
423
13
24
-
764
435
- Angle in degrees
- 2296b093-286c-438d-aa59-465d23147f1c
- Degrees
- D
- false
- 0
-
799
423
17
24
-
807.5
435
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- d68f5884-1ed1-4bd5-ab64-b7040370d59b
- Construct Point
- Pt
-
392
101
67
64
-
423
133
- {x} coordinate
- b9e9716b-aaed-4e63-90f0-fd69bffec388
- X coordinate
- X
- false
- 0
-
394
103
14
20
-
402.5
113
- 1
- 1
- {0}
- 0
- {y} coordinate
- 961e58c0-1cd5-49a0-8fd1-0e419a2c0b34
- Y coordinate
- Y
- false
- 0
-
394
123
14
20
-
402.5
133
- 1
- 1
- {0}
- 0
- {z} coordinate
- 54bdcf81-cd9a-447c-bad3-a55fe7ef5dc1
- Z coordinate
- Z
- false
- 0
-
394
143
14
20
-
402.5
153
- 1
- 1
- {0}
- 0
- Point coordinate
- 7451bc70-5fc3-43a3-bb48-ff10952414e7
- Point
- Pt
- false
- 0
-
438
103
19
60
-
447.5
133
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- 8cd6ad76-7f71-4948-8c5e-9a3e2549985f
- Construct Point
- Pt
-
392
173
67
64
-
423
205
- {x} coordinate
- cc48fd1f-8953-40bd-a5f6-a9a203bcabd4
- X coordinate
- X
- false
- 95f9fd7f-37dc-4bd8-8105-7301ef052bdd
- 1
-
394
175
14
20
-
402.5
185
- 1
- 1
- {0}
- 80
- {y} coordinate
- a1e74152-bea6-4daf-a4cf-bbaa027d9769
- Y coordinate
- Y
- false
- 0
-
394
195
14
20
-
402.5
205
- 1
- 1
- {0}
- 0
- {z} coordinate
- e34fa320-f5a3-4aaf-beaf-4207678e6e88
- Z coordinate
- Z
- false
- 0
-
394
215
14
20
-
402.5
225
- 1
- 1
- {0}
- 0
- Point coordinate
- d5104343-e872-4369-9a14-a75a852c1a15
- Point
- Pt
- false
- 0
-
438
175
19
60
-
447.5
205
- d5967b9f-e8ee-436b-a8ad-29fdcecf32d5
- Curve
- Contains a collection of generic curves
- d53a1087-053a-44d5-b485-68a8b5d09ce4
- Curve
- Crv
- false
- 1b8d948b-eedb-4c3c-bfba-ceaee74ff110
- 1
-
782
236
50
24
-
807.4463
248.7776
- 17b7152b-d30d-4d50-b9ef-c9fe25576fc2
- XY Plane
- World XY plane.
- true
- cc8dfb80-5022-4b13-83c9-a787888900e8
- XY Plane
- XY
-
474
246
64
28
-
505
260
- Origin of plane
- 36223dd6-39d8-43d1-85f3-16523a2c0069
- Origin
- O
- false
- 0
-
476
248
14
24
-
484.5
260
- 1
- 1
- {0}
-
0
0
0
- World XY plane
- df7d1e6a-049f-4594-9fb2-7dda33d26e57
- Plane
- P
- false
- 0
-
520
248
16
24
-
528
260
- a4cd2751-414d-42ec-8916-476ebf62d7fe
- Radians
- Convert an angle specified in degrees to radians
- 072c5f2f-5efd-4587-8eb9-f4eacb6f59a9
- Radians
- Rad
-
478
365
64
28
-
509
379
- Angle in degrees
- 7201253d-ef74-40ae-8173-4b941b44547b
- Degrees
- D
- false
- 25d0b3b4-fc42-4433-a4bf-e70bfa828143
- 1
-
480
367
14
24
-
488.5
379
- Angle in radians
- c64ce2fc-64f4-4ffc-abb1-8343f67d6c30
- Radians
- R
- false
- 0
-
524
367
16
24
-
532
379
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 25d0b3b4-fc42-4433-a4bf-e70bfa828143
- Number Slider
- angle °
- false
- 0
-
160
370
295
20
-
160.2554
370.2197
- 2
- 1
- 0
- 170
- 0
- 0
- 110.7
- c98a6015-7a2f-423c-bc66-bdc505249b45
- Plane 3Pt
- Create a plane through three points.
- true
- 78631b64-b599-490f-b493-9d449559b6c0
- Plane 3Pt
- Pl 3Pt
-
-129
197
66
64
-
-98
229
- Origin point
- c03438e8-8e89-47d2-b5c9-ca10c981173e
- Point A
- A
- false
- c318333b-fa9e-426b-b869-991ed69f1b64
- 1
-
-127
199
14
20
-
-118.5
209
- X-direction point
- 88046baa-f5c6-4fbc-97be-c88ee826709d
- Point B
- B
- false
- 5252af42-8b65-437c-a487-5eac1156e2cc
- 1
-
-127
219
14
20
-
-118.5
229
- Orientation point
- 9ece8cd3-edbb-4986-9f6d-886138f5abd4
- Point C
- C
- false
- f4cf1901-0cd0-4475-9dd6-bf34f5ebc6e1
- 1
-
-127
239
14
20
-
-118.5
249
- Plane definition
- af793683-207b-4276-a8a1-cc931d61589e
- Plane
- Pl
- false
- 0
-
-83
199
18
60
-
-74
229
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- true
- 03b41596-1093-42df-8cb9-728ff4c83a73
- Construct Point
- Pt
-
-281
116
67
64
-
-250
148
- {x} coordinate
- 46b26c29-1295-4a56-90de-e2187690ca0a
- X coordinate
- X
- false
- 39c22776-a388-46d7-abe4-caaffd8004f9
- 1
-
-279
118
14
20
-
-270.5
128
- 1
- 1
- {0}
- 0
- {y} coordinate
- 05cdff1f-dab0-4d5c-8b53-f69ce1483ebc
- Y coordinate
- Y
- false
- 108fecb2-82c4-4ef7-b31a-2d6517c32268
- 1
-
-279
138
14
20
-
-270.5
148
- 1
- 1
- {0}
- 0
- {z} coordinate
- 1cd02656-25ae-4866-8098-c3757e985576
- Z coordinate
- Z
- false
- ca67e373-c39e-4d29-980d-1c76d91a2de9
- 1
-
-279
158
14
20
-
-270.5
168
- 1
- 1
- {0}
- 0
- Point coordinate
- c318333b-fa9e-426b-b869-991ed69f1b64
- Point
- Pt
- false
- 0
-
-235
118
19
60
-
-225.5
148
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 39c22776-a388-46d7-abe4-caaffd8004f9
- Number Slider
- false
- 0
-
-594
112
260
20
-
-593.6757
112.793
- 2
- 1
- 0
- 50
- -50
- 0
- 24.03
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 108fecb2-82c4-4ef7-b31a-2d6517c32268
- Number Slider
- false
- 0
-
-593
139
258
20
-
-592.4278
139.043
- 2
- 1
- 0
- 50
- -50
- 0
- -17.28
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- ca67e373-c39e-4d29-980d-1c76d91a2de9
- Number Slider
- false
- 0
-
-592
164
258
20
-
-591.1778
164.043
- 2
- 1
- 0
- 50
- -50
- 0
- -9.72
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- true
- 7d81920e-fe3b-4fcc-856a-7444755fcc4a
- Construct Point
- Pt
-
-284
208
67
64
-
-253
240
- {x} coordinate
- 5e590f17-28b6-4fcb-aeb8-acdb345f0c4b
- X coordinate
- X
- false
- abfd65c5-05aa-4b81-a108-6a5355e6816a
- 1
-
-282
210
14
20
-
-273.5
220
- 1
- 1
- {0}
- 0
- {y} coordinate
- 7d22d623-e49c-4769-b49e-88c16b2a4f4e
- Y coordinate
- Y
- false
- 81a1d1b0-c109-4a52-8403-b06d094902c8
- 1
-
-282
230
14
20
-
-273.5
240
- 1
- 1
- {0}
- 0
- {z} coordinate
- 0fafe809-64a8-4448-af4b-21caa924776e
- Z coordinate
- Z
- false
- b53d373c-ad33-4aaa-a8de-83a088e127a5
- 1
-
-282
250
14
20
-
-273.5
260
- 1
- 1
- {0}
- 0
- Point coordinate
- 5252af42-8b65-437c-a487-5eac1156e2cc
- Point
- Pt
- false
- 0
-
-238
210
19
60
-
-228.5
240
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- abfd65c5-05aa-4b81-a108-6a5355e6816a
- Number Slider
- false
- 0
-
-597
205
260
20
-
-596.1757
205.293
- 2
- 1
- 0
- 50
- -50
- 0
- 3.28
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 81a1d1b0-c109-4a52-8403-b06d094902c8
- Number Slider
- false
- 0
-
-595
230
258
20
-
-594.9278
230.293
- 2
- 1
- 0
- 50
- -50
- 0
- 0.25
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- b53d373c-ad33-4aaa-a8de-83a088e127a5
- Number Slider
- false
- 0
-
-594
256
258
20
-
-593.6778
256.543
- 2
- 1
- 0
- 50
- -50
- 0
- 18.96
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- true
- 759d1f2d-c1de-45b6-9548-4d3ad4b27781
- Construct Point
- Pt
-
-286
296
67
64
-
-255
328
- {x} coordinate
- 0ec6b789-6c06-4ce4-a442-c0cdb61b63ea
- X coordinate
- X
- false
- f24c7c6f-3341-48d7-b5dd-11493225c086
- 1
-
-284
298
14
20
-
-275.5
308
- 1
- 1
- {0}
- 0
- {y} coordinate
- cadc8592-52b0-4c3f-9cd8-6474d8000ca7
- Y coordinate
- Y
- false
- 2313a88f-2ff0-48dc-b09b-dee536af8862
- 1
-
-284
318
14
20
-
-275.5
328
- 1
- 1
- {0}
- 0
- {z} coordinate
- 003f761f-6321-417a-9a6f-83613eba8698
- Z coordinate
- Z
- false
- da887b2c-91f5-4fc7-b9b2-dd3c06bf079f
- 1
-
-284
338
14
20
-
-275.5
348
- 1
- 1
- {0}
- 0
- Point coordinate
- f4cf1901-0cd0-4475-9dd6-bf34f5ebc6e1
- Point
- Pt
- false
- 0
-
-240
298
19
60
-
-230.5
328
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- f24c7c6f-3341-48d7-b5dd-11493225c086
- Number Slider
- false
- 0
-
-598
294
260
20
-
-597.4257
294.043
- 2
- 1
- 0
- 50
- -50
- 0
- -7.63
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 2313a88f-2ff0-48dc-b09b-dee536af8862
- Number Slider
- false
- 0
-
-597
319
258
20
-
-596.1778
319.043
- 2
- 1
- 0
- 50
- -50
- 0
- -14.68
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- da887b2c-91f5-4fc7-b9b2-dd3c06bf079f
- Number Slider
- false
- 0
-
-595
345
258
20
-
-594.9278
345.293
- 2
- 1
- 0
- 50
- -50
- 0
- -6.5
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 5137ef09-783f-4981-a9ec-aa4f2fc8e019
- Number Slider
- height
- false
- 0
-
159
339
384
20
-
159.0849
339.4185
- 2
- 1
- 0
- 200
- 0
- 0
- 112.83
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 225afdb2-480f-435b-a1cb-84170b3afd2f
- Panel
- false
- 0
- 0d6fe24b-f96e-4e86-bad3-d29ae034394e
- 1
- Double click to edit panel content…
-
737
288
106
38
- 0
- 0
- 0
-
737.476
288.175
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 20228f31-e357-4d65-8747-46e12348391c
- Panel
- false
- 0
- 816f49f4-39a6-4705-80c7-e2a924ac1e0c
- 1
- Double click to edit panel content…
-
856
313
105
55
- 0
- 0
- 0
-
856.035
313.0428
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 7c2a1ac2-4916-4aa3-9b0a-566a67f36e60
- Panel
- false
- 0
- b00909dc-b385-4e3e-a3a8-9e76efdaadeb
- 1
- Double click to edit panel content…
-
736
348
108
38
- 0
- 0
- 0
-
736.4249
348.559
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- aaa665bd-fd6e-4ccb-8d2c-c5b33072125d
- Curvature
- Evaluate the curvature of a curve at a specified parameter.
- true
- 40932656-6c80-4daa-9ad2-8cf8b338fc8d
- Curvature
- Curvature
-
1151
798
65
64
-
1182
830
- Curve to evaluate
- ef98c1a5-25c1-49b1-b59b-6afb9264b710
- Curve
- C
- false
- 12b4fe3c-7f43-444b-be77-19b89104763b
- 1
-
1153
800
14
30
-
1161.5
815
- Parameter on curve domain to evaluate
- bb19201b-82f6-46a3-968e-8457acb1864d
- Parameter
- t
- false
- 3dad486f-e4dc-4c1a-a3e3-edd2e0fd1459
- 1
-
1153
830
14
30
-
1161.5
845
- Point on curve at {t}
- 6666272a-5753-4a2f-bade-d2d52bc5e52d
- Point
- P
- false
- 0
-
1197
800
17
20
-
1205.5
810
- Curvature vector at {t}
- aa220db5-3068-4ca2-8821-8b9c90d1979a
- Curvature
- K
- false
- 0
-
1197
820
17
20
-
1205.5
830
- Curvature circle at {t}
- 10cf8192-1856-476a-b1e6-4b0f3c70a20b
- Curvature
- C
- false
- 0
-
1197
840
17
20
-
1205.5
850
- 6b021f56-b194-4210-b9a1-6cef3b7d0848
- Evaluate Length
- Evaluate a curve at a certain factor along its length. Length factors can be supplied both in curve units and normalized units. Change the [N] parameter to toggle between the two modes.
- true
- 7a3bf5ad-d8df-4c78-ab33-33f2a1b8fdd3
- Evaluate Length
- Eval
-
1057
823
64
64
-
1088
855
- Curve to evaluate
- 315efe79-3e18-4f12-9a9f-48c3fd619f70
- Curve
- C
- false
- 12b4fe3c-7f43-444b-be77-19b89104763b
- 1
-
1059
825
14
20
-
1067.5
835
- Length factor for curve evaluation
- 2bfe1d34-4f3b-4bb0-be9e-0296d2d11a85
- Length
- L
- false
- 6f2330d2-0e46-4e09-9ac5-7b7d2a1d3954
- 1
-
1059
845
14
20
-
1067.5
855
- 1
- 1
- {0}
- 0.5
- If True, the Length factor is normalized (0.0 ~ 1.0)
- 768df78b-ea9f-4024-8585-81b6a0c10891
- Normalized
- N
- false
- 0
-
1059
865
14
20
-
1067.5
875
- 1
- 1
- {0}
- true
- Point at the specified length
- d2445ed4-e075-4562-b765-47e17a5185ca
- Point
- P
- false
- 0
-
1103
825
16
20
-
1111
835
- Tangent vector at the specified length
- 5a606323-3c66-46dd-a374-a92dc7ab1c86
- Tangent
- T
- false
- 0
-
1103
845
16
20
-
1111
855
- Curve parameter at the specified length
- 3dad486f-e4dc-4c1a-a3e3-edd2e0fd1459
- Parameter
- t
- false
- 0
-
1103
865
16
20
-
1111
875
- 23862862-049a-40be-b558-2418aacbd916
- Deconstruct Arc
- Retrieve the base plane, radius and angle domain of an arc.
- true
- 55c865ff-19b4-4378-9996-badcb44a9589
- Deconstruct Arc
- DArc
-
1267
847
65
64
-
1298
879
- Arc or Circle to deconstruct
- e0a2a9c6-de9b-4ae3-854d-8bf414396827
- Arc
- A
- false
- 10cf8192-1856-476a-b1e6-4b0f3c70a20b
- 1
-
1269
849
14
60
-
1277.5
879
- Base plane of arc or circle
- 81d935f9-4a1b-49ca-b92c-718561d9b488
- Base Plane
- B
- false
- 0
-
1313
849
17
20
-
1321.5
859
- Radius of arc or circle
- 64504e23-6a31-41c8-aef7-9ea0c21e3465
- Radius
- R
- false
- 0
-
1313
869
17
20
-
1321.5
879
- Angle domain (in radians) of arc
- 3c6d7169-cc80-4199-8fef-ce0a92463c3a
- Angle
- A
- false
- 0
-
1313
889
17
20
-
1321.5
899
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- a04f3471-a7fc-4cd9-b101-bb6f71dec549
- Panel
- false
- 0
- 64504e23-6a31-41c8-aef7-9ea0c21e3465
- 1
- Double click to edit panel content…
-
1377
830
96
42
- 0
- 0
- 0
-
1377.688
830.6463
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- f12daa2f-4fd5-48c1-8ac3-5dea476912ca
- Mirror
- Mirror an object.
- 864b9457-bf65-45dc-a49e-8e972abffb2b
- Mirror
- Mirror
-
1277
665
65
44
-
1308
687
- Base geometry
- ef1ac667-f8c6-4a26-800e-9f64490f8b70
- Geometry
- G
- true
- 12b4fe3c-7f43-444b-be77-19b89104763b
- 10cf8192-1856-476a-b1e6-4b0f3c70a20b
- 2
-
1279
667
14
20
-
1287.5
677
- Mirror plane
- fb82719d-d33e-4bcc-ab84-9035150adc96
- Plane
- P
- false
- 0654eb92-001e-43e0-b38a-58a5d0d80f8e
- 1
-
1279
687
14
20
-
1287.5
697
- 1
- 1
- {0}
-
0
0
0
0
0
1
1
0
0
- Mirrored geometry
- fef45908-0b4b-4554-b56b-334d7b9a07c0
- Geometry
- G
- false
- 0
-
1323
667
17
20
-
1331.5
677
- Transformation data
- b1d2e017-d6c1-487a-925f-7e6b3170b50c
- Transform
- X
- false
- 0
-
1323
687
17
20
-
1331.5
697
- 9df5e896-552d-4c8c-b9ca-4fc147ffa022
- Expression
- Evaluate an expression
- x*2
- 8a2af1f2-b070-42bc-acff-393a560d94c6
- Expression
- Expression
-
1379
892
84
28
-
1419
906
- 1
- ba80fd98-91a1-4958-b6a7-a94e40e52bdb
- 1
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- Expression variable
- 9378e904-7029-4099-9a7d-0a61740c8db5
- Variable x
- x
- true
- 64504e23-6a31-41c8-aef7-9ea0c21e3465
- 1
-
1381
894
12
24
-
1388.5
906
- Result of expression
- ae803c56-82b6-4b49-9bf4-1997a330a545
- Result
- R
- false
- 0
-
1445
894
16
24
-
1453
906
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 7ff6881c-7677-4071-a632-b6c8ea1ac4d3
- Panel
- false
- 0
- ae803c56-82b6-4b49-9bf4-1997a330a545
- 1
- Double click to edit panel content…
-
1489
887
96
42
- 0
- 0
- 0
-
1489.256
887.1902
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 0068d51d-c81e-4187-8df3-5835ab363a73
- Panel
- false
- 0
- 0
- 71.7
-
486
1016
50
20
- 0
- 0
- 0
-
486.351
1016.602
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 65023053-5666-4c0b-b753-08fe81bad98b
- Panel
- false
- 0
- 0
- 0.09
-
51
1103
50
20
- 0
- 0
- 0
-
51.64487
1103.176
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- b958296d-1f29-45e4-a204-834500f3a2c8
- Panel
- false
- 0
- 0
- 0.0055
-
50
1130
62
20
- 0
- 0
- 0
-
50.66486
1130.595
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 9df5e896-552d-4c8c-b9ca-4fc147ffa022
- Expression
- Evaluate an expression
- π*(outer^4-(outer-thick)^4)/32
- c6fb6177-2d5c-4ea6-801e-f1d602a9945f
- Expression
- Expression
-
197
1105
324
44
-
366
1127
- 2
- ba80fd98-91a1-4958-b6a7-a94e40e52bdb
- ba80fd98-91a1-4958-b6a7-a94e40e52bdb
- 1
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- Expression variable
- cf3ef3e5-5024-4f5c-a4c6-0baf27546401
- Variable outer
- outer
- true
- 65023053-5666-4c0b-b753-08fe81bad98b
- 1
-
199
1107
30
20
-
215.5
1117
- Expression variable
- 275aff5f-fca5-430e-bd77-af734dc26d01
- Variable thick
- thick
- true
- b958296d-1f29-45e4-a204-834500f3a2c8
- 1
-
199
1127
30
20
-
215.5
1137
- Result of expression
- c29e43b1-f147-4596-9a27-65e202efbf44
- Result
- R
- false
- 0
-
503
1107
16
40
-
511
1127
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 61e14a85-7063-4c93-bec1-f130a2a79f94
- Panel
- false
- 0
- 20b5374e-e220-4840-8424-dcf1b57d3ad2
- 1
- Double click to edit panel content…
-
744
1065
97
58
- 0
- 0
- 0
-
744.1909
1065.401
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- d5967b9f-e8ee-436b-a8ad-29fdcecf32d5
- Curve
- Contains a collection of generic curves
- 9ce607e3-994c-4bda-99e3-6e421454263b
- Curve
- Crv
- false
- 10cf8192-1856-476a-b1e6-4b0f3c70a20b
- 1
-
1303
728
50
24
-
1328.596
740.7537
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
147.2881
1085.861
-
504.9157
1084.888
-
504.9566
1099.915
-
147.329
1100.889
- A quick note
- Microsoft Sans Serif
- a2b3599b-d7ad-4dff-aca4-d6dbc30755af
- false
- Scribble
- Scribble
- 16
- area moment of inertia for a hollow rod (in m^4)
-
142.2881
1079.888
367.6685
26.00085
-
147.2881
1085.861
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
544.7806
1376.747
-
735.764
1376.736
-
735.7651
1391.763
-
544.7817
1391.774
- A quick note
- Microsoft Sans Serif
- 37f949de-70f1-4437-96b3-797739d591c1
- false
- Scribble
- Scribble
- 16
- One height, two solutions
-
539.7806
1371.736
200.9845
25.03821
-
544.7806
1376.747
- 079bd9bd-54a0-41d4-98af-db999015f63d
- VB Script
- Private Function IsSet(ByVal param As String) As Boolean ' Check if an input parameter has data
Dim i As Integer = Component.Params.IndexOfInputParam(param)
If i > -1 Then
Return Component.Params.Input.ElementAt(i).DataType > 1 ' input parameter DataType of 1 means it's not receiving input (internal or external)
Else
Msg("error", "Input parameter '" & param & "' not found")
Return False
End If
End Function
Private Sub Msg(ByVal type As String, ByVal msg As String) ' Output an error, warning, or informational message
Select Case type
Case "error"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, msg)
Print("Error: " & msg)
Case "warning"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, msg)
Print("Warning: " & msg)
Case "info"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, msg)
Print(msg)
End Select
End Sub
' Solve for the m parameter from length and width (reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m))
Private Function SolveMFromLenWid(ByVal L As Double, ByVal w As Double) As Double
If w = 0 Then
Return Defined.M_ZERO_W ' for the boundry condition width = 0, bypass the function and return the known m value
End If
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwl As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwl = 2 * EllipticE(m) / EllipticK(m) - 1 ' calculate w/L with the test value of m
If cwl < w / L Then ' compares the calculated w/L with the actual w/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Solve for the m parameter from length and height (reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m))
' Note that it's actually possible to find 2 valid values for m (hence 2 width values) at certain height values
Private Function SolveMFromLenHt(ByVal L As Double, ByVal h As Double) As List(Of Double)
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim twoWidths As Boolean = h / L >= Defined.DOUBLE_W_HL_RATIO And h / L < Defined.MAX_HL_RATIO ' check to see if h/L is within the range where 2 solutions for the width are possible
Dim m As Double
Dim mult_m As New List(Of Double)
Dim chl As Double
If twoWidths Then
' find the first of two possible solutions for m with the following limits:
lower = Defined.M_DOUBLE_W ' see constants at bottom of script
upper = Defined.M_MAXHEIGHT ' see constants at bottom of script
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
' then find the second of two possible solutions for m with the following limits:
lower = Defined.M_MAXHEIGHT ' see constants at bottom of script
upper = 1
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl < h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
If m <= Defined.M_MAX Then ' return this m parameter only if it falls within the maximum useful value (above which the curve breaks down)
mult_m.Add(m)
End If
Else
' find the one possible solution for the m parameter
upper = Defined.M_DOUBLE_W ' limit the upper end of the search to the maximum value of m for which only one solution exists
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
End If
Return mult_m
End Function
' Solve for the m parameter from width and height (derived from reference {1} equations (33) and (34) with same notes as above)
Private Function SolveMFromWidHt(ByVal w As Double, ByVal h As Double) As Double
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwh As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwh = (2 * EllipticE(m) - EllipticK(m)) / Math.Sqrt(m) ' calculate w/h with the test value of m
If cwh < w / h Then ' compares the calculated w/h with the actual w/h then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Calculate length based on height and an m parameter, derived from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_L(ByVal h As Double, ByVal m As Double) As Double
Return h * EllipticK(m) / Math.Sqrt(m)
End Function
' Calculate width based on length and an m parameter, derived from reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m)
Private Function Cal_W(ByVal L As Double, ByVal m As Double) As Double
Return L * (2 * EllipticE(m) / EllipticK(m) - 1)
End Function
' Calculate height based on length and an m parameter, from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_H(ByVal L As Double, ByVal m As Double) As Double
Return L * Math.Sqrt(m) / EllipticK(m)
End Function
' Calculate the unique m parameter based on a start tangent angle, from reference {2}, just above equation (9a), that states k = Sin(angle / 2 + Pi / 4),
' but as m = k^2 and due to this script's need for an angle rotated 90° versus the one in reference {1}, the following formula is the result
' New note: verified by reference {4}, pg. 78 at the bottom
Private Function Cal_M(ByVal a As Double) As Double
Return (1 - Math.Cos(a)) / 2 ' equal to Sin^2(a/2) too
End Function
' Calculate start tangent angle based on an m parameter, derived from above formula
Private Function Cal_A(ByVal m As Double) As Double
Return Math.Acos(1 - 2 * m)
End Function
' This is the heart of this script, taking the found (or specified) length, width, and angle values along with the found m parameter to create
' a list of points that approximate the shape or form of the elastica. It works by finding the x and y coordinates (which are reversed versus
' the original equations (12a) and (12b) from reference {2} due to the 90° difference in orientation) based on the tangent angle along the curve.
' See reference {2} for more details on how they derived it. Note that to simplify things, the algorithm only calculates the points for half of the
' curve, then mirrors those points along the y-axis.
Private Function FindBendForm(ByVal L As Double, ByVal w As Double, ByVal m As Double, ByVal ang As Double, ByVal refPln As Plane) As List(Of Point3d)
L = L / 2 ' because the below algorithm is based on the formulas in reference {2} for only half of the curve
w = w / 2 ' same
If ang = 0 Then ' if angle (and height) = 0, then simply return the start and end points of the straight line
Dim out As New List(Of Point3d)
out.Add(refPln.PointAt(w, 0, 0))
out.Add(refPln.PointAt(-w, 0, 0))
Return out
End If
Dim x As Double
Dim y As Double
Dim halfCurvePts As New List(Of Point3d)
Dim fullCurvePts As New List(Of Point3d)
Dim translatedPts As New List(Of Point3d)
ang -= Math.PI / 2 ' a hack to allow this algorithm to work, since the original curve in paper {2} was rotated 90°
Dim angB As Double = ang + (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' angB is the 'lowercase theta' which should be in formula {2}(12b) as the interval
' start [a typo...see equation(3)]. It's necessary to start angB at ang + [interval] instead of just ang due to integration failing at angB = ang
halfCurvePts.Add(New Point3d(w, 0, 0)) ' start with this known initial point, as integration will fail when angB = ang
' each point {x, y} is calculated from the tangent angle, angB, that occurs at each point (which is why this iterates from ~ang to -pi/2, the known end condition)
Do While Math.Round(angB, Defined.ROUNDTO) >= Math.Round(-Math.PI / 2, Defined.ROUNDTO)
y = (Math.Sqrt(2) * Math.Sqrt(Math.Sin(ang) - Math.Sin(angB)) * (w + L)) / (2 * EllipticE(m)) ' note that x and y are swapped vs. (12a) and (12b)
x = (L / (Math.Sqrt(2) * EllipticK(m))) * Simpson(angB, -Math.PI / 2, 500, ang) ' calculate the Simpson approximation of the integral (function f below)
' over the interval angB ('lowercase theta') to -pi/2. side note: is 500 too few iterations for the Simson algorithm?
If Math.Round(x, Defined.ROUNDTO) = 0 Then x = 0
halfCurvePts.Add(New Point3d(x, y, 0))
angB += (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' onto the next tangent angle
Loop
' After finding the x and y values for half of the curve, add the {-x, y} values for the rest of the curve
For Each point As Point3d In halfCurvePts
If Math.Round(point.X, Defined.ROUNDTO) = 0 Then
If Math.Round(point.Y, Defined.ROUNDTO) = 0 Then
fullCurvePts.Add(New Point3d(0, 0, 0)) ' special case when width = 0: when x = 0, only duplicate the point when y = 0 too
End If
Else
fullCurvePts.Add(New Point3d(-point.X, point.Y, 0))
End If
Next
halfCurvePts.Reverse
fullCurvePts.AddRange(halfCurvePts)
For Each p As Point3d In fullCurvePts
translatedPts.Add(refPln.PointAt(p.X, p.Y, p.Z)) ' translate the points from the reference plane to the world plane
Next
Return translatedPts
End Function
' Interpolates the points from FindBendForm to create the Elastica curve. Uses start & end tangents for greater accuracy.
Private Function MakeCurve(ByVal pts As List(Of Point3d), ByVal ang As Double, ByVal refPln As Plane) As Curve
If ang <> 0 Then
Dim ts, te As New Vector3d(refPln.XAxis)
ts.Rotate(ang, refPln.ZAxis)
te.Rotate(-ang, refPln.ZAxis)
Return Curve.CreateInterpolatedCurve(pts, 3, CurveKnotStyle.Chord, ts, te) ' 3rd degree curve with 'Chord' Knot Style
Else
Return Curve.CreateInterpolatedCurve(pts, 3) ' if angle (and height) = 0, then simply interpolate the straight line (no start/end tangents)
End If
End Function
' Implements the Simpson approximation for an integral of function f below
Public Function Simpson(a As Double, b As Double, n As Integer, theta As Double) As Double 'n should be an even number
Dim j As Integer, s1 As Double, s2 As Double, h As Double
h = (b - a) / n
s1 = 0
s2 = 0
For j = 1 To n - 1 Step 2
s1 = s1 + fn(a + j * h, theta)
Next j
For j = 2 To n - 2 Step 2
s2 = s2 + fn(a + j * h, theta)
Next j
Simpson = h / 3 * (fn(a, theta) + 4 * s1 + 2 * s2 + fn(b, theta))
End Function
' Specific calculation for the above integration
Public Function fn(x As Double, theta As Double) As Double
fn = Math.Sin(x) / (Math.Sqrt(Math.Sin(theta) - Math.Sin(x))) ' from reference {2} formula (12b)
End Function
' Return the Complete Elliptic integral of the 1st kind
' Abramowitz and Stegun p.591, formula 17.3.11
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticK(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum += Math.Pow(m, i) * Math.Pow(term, 2)
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
' Return the Complete Elliptic integral of the 2nd kind
' Abramowitz and Stegun p.591, formula 17.3.12
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticE(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum -= Math.Pow(m, i) * Math.Pow(term, 2) / above
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
Friend Partial NotInheritable Class Defined
Private Sub New()
End Sub
' Note: most of these values for m and h/L ratio were found with Wolfram Alpha and either specific intercepts (x=0) or local minima/maxima. They should be constant.
Public Const M_SKETCHY As Double = 0.95 ' value of the m parameter where the curvature near the ends of the curve gets wonky
Public Const M_MAX As Double = 0.993 ' maximum useful value of the m parameter, above which this algorithm for the form of the curve breaks down
Public Const M_ZERO_W As Double = 0.826114765984970336 ' value of the m parameter when width = 0
Public Const M_MAXHEIGHT As Double = 0.701327460663101223 ' value of the m parameter at maximum possible height of the bent rod/wire
Public Const M_DOUBLE_W As Double = 0.180254422335013983 ' minimum value of the m parameter when two width values are possible for a given height and length
Public Const DOUBLE_W_HL_RATIO As Double = 0.257342117984635757 ' value of the height/length ratio above which there are two possible width values
Public Const MAX_HL_RATIO As Double = 0.403140189705650243 ' maximum possible value of the height/length ratio
Public Const MAXERR As Double = 0.0000000001 ' error tolerance
Public Const MAXIT As Integer = 100 ' maximum number of iterations
Public Const ROUNDTO As Integer = 10 ' number of decimal places to round off to
Public Const CURVEDIVS As Integer = 50 ' number of sample points for building the curve (or half-curve as it were)
End Class
- A VB.NET scriptable component
-
98
86
- true
- 34e9c6ff-5f0a-453a-89bb-504c40c19604
- VB Script
- VB
- true
- 0
- ' -----------------------------------------------------------------
' Elastic Bending Script by Will McElwain
' Created February 2014
'
' DESCRIPTION:
' This beast creates the so-called 'elastica curve', the shape a long, thin rod or wire makes when it is bent elastically (i.e. not permanently). In this case, force
' is assumed to only be applied horizontally (which would be in line with the rod at rest) and both ends are assumed to be pinned or hinged meaning they are free
' to rotate (as opposed to clamped, when the end tangent angle is fixed, usually horizontally). An interesting finding is that it doesn't matter what the material or
' cross-sectional area is, as long as they're uniform along the entire length. Everything makes the same shape when bent as long as it doesn't cross the threshold
' from elastic to plastic (permanent) deformation (I don't bother to find that limit here, but can be found if the yield stress for a material is known).
'
' Key to the formulas used in this script are elliptic integrals, specifically K(m), the complete elliptic integral of the first kind, and E(m), the complete elliptic
' integral of the second kind. There was a lot of confusion over the 'm' and 'k' parameters for these functions, as some people use them interchangeably, but they are
' not the same. m = k^2 (thus k = Sqrt(m)). I try to use the 'm' parameter exclusively to avoid this confusion. Note that there is a unique 'm' parameter for every
' configuration/shape of the elastica curve.
'
' This script tries to find that unique 'm' parameter based on the inputs. The algorithm starts with a test version of m, evaluates an expression, say 2*E(m)/K(m)-1,
' then compares the result to what it should be (in this case, a known width/length ratio). Iterate until the correct m is found. Once we have m, we can then calculate
' all of the other unknowns, then find points that lie on that curve, then interpolate those points for the actual curve. You can also use Wolfram|Alpha as I did to
' find the m parameter based on the equations in this script (example here: http://tiny.cc/t4tpbx for when say width=45.2 and length=67.1).
'
' Other notes:
' * This script works with negative values for width, which will creat a self-intersecting curve (as it should). The curvature of the elastica starts to break down around
' m=0.95 (~154°), but this script will continue to work until M_MAX, m=0.993 (~169°). If you wish to ignore self-intersecting curves, set ignoreSelfIntersecting to True
' * When the only known values are length and height, it is actually possible for certain ratios of height to length to have two valid m values (thus 2 possible widths
' and angles). This script will return them both.
' * Only the first two valid parameters (of the required ones) will be used, meaning if all four are connected (length, width or a PtB, height, and angle), this script will
' only use length and width (or a PtB).
' * Depending on the magnitude of your inputs (say if they're really small, like if length < 10), you might have to increase the constant ROUNDTO at the bottom
'
' REFERENCES:
' {1} "The elastic rod" by M.E. Pacheco Q. & E. Pina, http://www.scielo.org.mx/pdf/rmfe/v53n2/v53n2a8.pdf
' {2} "An experiment in nonlinear beam theory" by A. Valiente, http://www.deepdyve.com/lp/doc/I3lwnxdfGz , also here: http://tiny.cc/Valiente_AEiNBT
' {3} "Snap buckling, writhing and Loop formation In twisted rods" by V.G.A. GOSS, http://myweb.lsbu.ac.uk/~gossga/thesisFinal.pdf
' {4} "Theory of Elastic Stability" by Stephen Timoshenko, http://www.scribd.com/doc/50402462/Timoshenko-Theory-of-Elastic-Stability (start on p. 76)
'
' INPUT:
' PtA - First anchor point (required)
' PtB - Second anchor point (optional, though 2 out of the 4--length, width, height, angle--need to be specified)
' [note that PtB can be the same as PtA (meaning width would be zero)]
' [also note that if a different width is additionally specified that's not equal to the distance between PtA and PtB, then the end point will not equal PtB anymore]
' Pln - Plane of the bent rod/wire, which bends up in the +y direction. The line between PtA and PtB (if specified) must be parallel to the x-axis of this plane
'
' ** 2 of the following 4 need to be specified **
' Len - Length of the rod/wire, which needs to be > 0
' Wid - Width between the endpoints of the curve [note: if PtB is specified in addition, and distance between PtA and PtB <> width, the end point will be relocated
' Ht - Height of the bent rod/wire (when negative, curve will bend downward, relative to the input plane, instead)
' Ang - Inner departure angle or tangent angle (in radians) at the ends of the bent rod/wire. Set up so as width approaches length (thus height approaches zero), angle approaches zero
'
' * Following variables only needed for optional calculating of bending force, not for shape of curve.
' E - Young's modulus (modulus of elasticity) in GPa (=N/m^2) (material-specific. for example, 7075 aluminum is roughly 71.7 GPa)
' I - Second moment of area (or area moment of inertia) in m^4 (cross-section-specific. for example, a hollow rod
' would have I = pi * (outer_diameter^4 - inner_diameter^4) / 32
' Note: E*I is also known as flexural rigidity or bending stiffness
'
' OUTPUT:
' out - only for debugging messages
' Pts - the list of points that approximate the shape of the elastica
' Crv - the 3rd-degree curve interpolated from those points (with accurate start & end tangents)
' L - the length of the rod/wire
' W - the distance (width) between the endpoints of the rod/wire
' H - the height of the bent rod/wire
' A - the tangent angle at the (start) end of the rod/wire
' F - the force needed to hold the rod/wire in a specific shape (based on the material properties & cross-section) **be sure your units for 'I' match your units for the
' rest of your inputs (length, width, etc.). Also note that the critical buckling load (force) that makes the rod/wire start to bend can be found at height=0
'
' THANKS TO:
' Mårten Nettelbladt (thegeometryofbending.blogspot.com)
' Daniel Piker (Kangaroo plugin)
' David Rutten (Grasshopper guru)
' Euler & Bernoulli (the O.G.'s)
'
' -----------------------------------------------------------------
Dim ignoreSelfIntersecting As Boolean = False ' set to True if you don't want to output curves where width < 0, which creates a self-intersecting curve
Dim inCt As Integer = 0 ' count the number of required parameters that are receiving data
Dim length As Double
Dim width As System.Object = Nothing ' need to set as Nothing so we can check if it has been assigned a value later
Dim height As Double
Dim angle As Double
Dim m As Double
Dim multiple_m As New List(Of Double)
Dim AtoB As Line
Dim flip_H As Boolean = False ' if height is negative, this flag will be set
Dim flip_A As Boolean = False ' if angle is negative, this flag will be set
If Not IsSet("Pln") Then
Msg("error", "Base plane is not set")
Return
End If
If Not IsSet("PtA") Then
Msg("error", "Point A is not set")
Return
End If
If Math.Round(Pln.DistanceTo(PtA), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point A is not on the base plane")
Return
End If
Dim refPlane As Plane = Pln ' create a reference plane = input plane and set the origin of it to PtA in case PtA isn't the origin already
refPlane.Origin = PtA
If IsSet("PtB") Then
If Math.Round(Pln.DistanceTo(PtB), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point B is not on the base plane")
Return
End If
AtoB = New Line(PtA, PtB)
If AtoB.Length <> 0 And Not AtoB.Direction.IsPerpendicularTo(Pln.YAxis) Then
Msg("error", "The line between PtA and PtB is not perpendicular to the Y-axis of the specified plane")
Return
End If
inCt += 1
If IsSet("Wid") Then Msg("info", "Wid will override the distance between PtA and PtB. If you do not want this to happen, disconnect PtB or Wid.")
width = PtA.DistanceTo(PtB) ' get the width (distance) between PtA and PtB
Dim refPtB As Point3d
refPlane.RemapToPlaneSpace(PtB, refPtB)
If refPtB.X < 0 Then width = -width ' check if PtB is to the left of PtA...if so, width is negative
End If
If IsSet("Len") Then inCt += 1
If IsSet("Wid") Then inCt += 1
If IsSet("Ht") Then inCt += 1
If IsSet("Ang") Then inCt += 1
If inCt > 2 Then Msg("info", "More parameters set than are required (out of length, width, height, angle). Only using the first two valid ones.")
' check for connected/specified inputs. note: only the first two that it comes across will be used
If IsSet("Len") Then ' if length is specified then...
If Len <= 0 Then
Msg("error", "Length cannot be negative or zero")
Return
End If
If IsSet("Wid") Then ' find height & angle based on length and specified width
If Wid > Len Then
Msg("error", "Width is greater than length")
Return
End If
If Wid = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
width = Wid
Else
m = SolveMFromLenWid(Len, Wid)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
width = Wid
End If
Else If width IsNot Nothing Then ' find height & angle based on length and calculated width (distance between PtA and PtB)
If width > Len Then
Msg("error", "Width is greater than length")
Return
End If
If width = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
Else
m = SolveMFromLenWid(Len, width)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
Else If IsSet("Ht") Then ' find width & angle based on length and height ** possible to return 2 results **
If Math.Abs(Ht / Len) > Defined.MAX_HL_RATIO Then
Msg("error", "Height not possible with given length")
Return
End If
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
width = Len
angle = 0
Else
multiple_m = SolveMFromLenHt(Len, Ht) ' note that it's possible for two values of m to be found if height is close to max height
If multiple_m.Count = 1 Then ' if there's only one m value returned, calculate the width & angle here. we'll deal with multiple m values later
m = multiple_m.Item(0)
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
End If
height = Ht
Else If IsSet("Ang") Then ' find width & height based on length and angle
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
width = Len
height = 0
Else
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to length")
Return
End If
length = Len
Else If IsSet("Wid") Then ' if width is specified then...
If IsSet("Ht") Then ' find length & angle based on specified width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = Wid
angle = 0
Else
m = SolveMFromWidHt(Wid, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on specified width and angle
If Wid = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = Wid
height = 0
Else
length = Wid / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to width (Wid)")
Return
End If
width = Wid
Else If width IsNot Nothing Then ' if width is determined by PtA and PtB then...
If IsSet("Ht") Then ' find length & angle based on calculated width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = width
angle = 0
Else
m = SolveMFromWidHt(width, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on calculated width and angle
If width = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = width
height = 0
Else
length = width / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to PtA and PtB")
Return
End If
Else If IsSet("Ht") Then ' if height is specified then...
If IsSet("Ang") Then ' find length & width based on height and angle
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_H = True
flip_A = True
End If
If Ht = 0 Then
Msg("error", "Height can't = 0 if only height and angle are specified")
Return
Else
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = Not flip_A
flip_H = Not flip_H
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then
Msg("error", "Angle can't = 0 if only height and angle are specified")
Return
Else
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
width = Cal_W(length, m) ' L * (2 * E(m) / K(m) - 1)
End If
angle = Ang
End If
height = Ht
Else
Msg("error", "Need to specify one more parameter in addition to height")
Return
End If
Else If IsSet("Ang") Then
Msg("error", "Need to specify one more parameter in addition to angle")
Return
Else
Msg("error", "Need to specify two of the four parameters: length, width (or PtB), height, and angle")
Return
End If
If m > Defined.M_MAX Then
Msg("error", "Form of curve not solvable with current algorithm and given inputs")
Return
End If
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
If multiple_m.Count > 1 Then ' if there is more than one m value returned, calculate the width, angle, and curve for each
Dim multi_pts As New DataTree(Of Point3d)
Dim multi_crv As New List(Of Curve)
Dim tmp_pts As New List(Of Point3d)
Dim multi_W, multi_A, multi_F As New List(Of Double)
Dim j As Integer = 0 ' used for creating a new branch (GH_Path) for storing pts which is itself a list of points
For Each m_val As Double In multiple_m
width = Cal_W(length, m_val) 'length * (2 * EllipticE(m_val) / EllipticK(m_val) - 1)
If width < 0 And ignoreSelfIntersecting Then
Msg("warning", "One curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Continue For
End If
If m_val >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve whose width = " & Math.Round(width, 4) & " is not guaranteed")
angle = Cal_A(m_val) 'Math.Asin(2 * m_val - 1)
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
tmp_pts = FindBendForm(length, width, m_val, angle, refPlane)
multi_pts.AddRange(tmp_pts, New GH_Path(j))
multi_crv.Add(MakeCurve(tmp_pts, angle, refPlane))
multi_W.Add(width)
If flip_A Then angle = -angle
multi_A.Add(angle)
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
multi_F.Add(EllipticK(m_val) ^ 2 * E * I / length ^ 2) ' from reference {4} pg. 79
j += 1
refPlane.Origin = PtA ' reset the reference plane origin to PtA for the next m_val
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m_val & ", k=" & Math.Sqrt(m_val) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
Next
' assign the outputs
Pts = multi_pts
Crv = multi_crv
L = length
W = multi_W
If flip_H Then height = -height
H = height
A = multi_A
F = multi_F
Else ' only deal with the single m value
If m >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve at these parameters is not guaranteed")
If width < 0 And ignoreSelfIntersecting Then
Msg("error", "Curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Return
End If
Pts = FindBendForm(length, width, m, angle, refPlane)
Crv = MakeCurve(pts, angle, refPlane)
L = length
W = width
If flip_H Then height = -height
H = height
If flip_A Then angle = -angle
A = angle
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
F = EllipticK(m) ^ 2 * E * I / length ^ 2 ' from reference {4} pg. 79. Note: the critical buckling (that makes the rod/wire start to bend) can be found at height=0 (width=length)
'height = Math.Sqrt(((2 * Len / 5) ^ 2 - ((Wid - Len / 5) / 2) ^ 2) ' quick approximation discovered by Mårten of 'Geometry of Bending' fame ( http://tiny.cc/it2pbx )
'width = (Len +/- 2 * Math.Sqrt(4 * Len ^ 2 - 25 * Ht ^ 2)) / 5 ' derived from above
'length = (2 * Math.Sqrt(15 * Ht ^ 2 + 4 * Wid ^ 2) - Wid) / 3 ' derived from above
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m & ", k=" & Math.Sqrt(m) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
End If
-
615
822
84
184
-
657
914
- 9
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 8
- 3ede854e-c753-40eb-84cb-b48008f14fd4
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- true
- Script Variable PtA
- e44ef3d7-d80d-4847-b3c9-7145c5d256c7
- PtA
- PtA
- true
- 0
- true
- 544607c8-b250-4465-bd1a-e6ed510b2090
- 1
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
617
824
25
20
-
631
834
- true
- Script Variable PtB
- f3a5f81b-cbeb-43a5-b9d7-95ddf8329091
- PtB
- PtB
- true
- 0
- true
- 0
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
617
844
25
20
-
631
854
- true
- Script Variable Pln
- 25fe63c8-a9a1-43dd-ba6c-ff444bb1bd38
- Pln
- Pln
- true
- 0
- true
- 2e367eec-73c9-49fe-931b-de57feb15198
- 1
- 3897522d-58e9-4d60-b38c-978ddacfedd8
-
617
864
25
20
-
631
874
- true
- Script Variable Len
- c645a879-0d63-4de2-8207-39e77ea0b36a
- Len
- Len
- true
- 0
- true
- 7e001f0c-1ecd-4198-95f7-0d0278815c2b
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
617
884
25
20
-
631
894
- true
- Script Variable Wid
- 563b27b8-1de0-4076-9540-f1f6287d4585
- Wid
- Wid
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
617
904
25
20
-
631
914
- true
- Script Variable Ht
- f945874f-3911-45dd-a65b-5931b59aaeda
- Ht
- Ht
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
617
924
25
20
-
631
934
- true
- Script Variable Ang
- 7cbb4f70-f9aa-4f07-bc67-aac4eaace9e1
- Ang
- Ang
- true
- 0
- true
- b2a8f43d-df9e-4385-bfbe-4e7a54acdc52
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
617
944
25
20
-
631
954
- true
- Script Variable E
- 757c9fbf-c87a-438c-9240-7ed119111c17
- E
- E
- true
- 0
- true
- 0068d51d-c81e-4187-8df3-5835ab363a73
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
617
964
25
20
-
631
974
- true
- Script Variable I
- dfba63c4-6cba-4504-bd15-6d7b03b308e0
- I
- I
- true
- 0
- true
- c29e43b1-f147-4596-9a27-65e202efbf44
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
617
984
25
20
-
631
994
- 1
- Print, Reflect and Error streams
- e74891fd-659b-4fdb-833d-cbae9b2064f7
- out
- out
- false
- 0
-
672
824
25
22
-
684.5
835.25
- Output parameter Pts
- 74a1959d-f66e-4c81-8b36-b26ed2379bb0
- Pts
- Pts
- false
- 0
-
672
846
25
23
-
684.5
857.75
- Output parameter Crv
- 9cf1549b-e355-4e34-8c66-56776a6693a3
- Crv
- Crv
- false
- 0
-
672
869
25
22
-
684.5
880.25
- Output parameter L
- 03e53700-d1d7-480a-9312-c1af517baedd
- L
- L
- false
- 0
-
672
891
25
23
-
684.5
902.75
- Output parameter W
- 09f794fe-078e-4e7b-840b-9d52b913b097
- W
- W
- false
- 0
-
672
914
25
22
-
684.5
925.25
- Output parameter H
- 2373426a-a151-4361-9f8e-d19fef664dc8
- H
- H
- false
- 0
-
672
936
25
23
-
684.5
947.75
- Output parameter A
- 619887fe-9427-4cea-b7fd-0b8e37ad0966
- A
- A
- false
- 0
-
672
959
25
22
-
684.5
970.25
- Output parameter F
- 20b5374e-e220-4840-8424-dcf1b57d3ad2
- F
- F
- false
- 0
-
672
981
25
23
-
684.5
992.75
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 7e001f0c-1ecd-4198-95f7-0d0278815c2b
- Number Slider
- length
- false
- 0
-
160
874
382
20
-
160.4443
874.5179
- 2
- 1
- 0
- 400
- 0
- 0
- 145.76
- fbac3e32-f100-4292-8692-77240a42fd1a
- Point
- Contains a collection of three-dimensional points
- true
- 37000574-d15c-4f7d-92d9-b148cb8b434c
- Point
- Pt
- false
- 74a1959d-f66e-4c81-8b36-b26ed2379bb0
- 1
-
784
791
50
24
-
809.0988
803.2372
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 982de226-ec32-4b13-b043-f53881d2e028
- Panel
- false
- 0
- 1487d807-5f9b-4abc-9b8d-effa22608b5d
- 1
- Double click to edit panel content…
-
849
986
105
55
- 0
- 0
- 0
-
849.9546
986.3983
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 0d77c51e-584f-44e8-aed2-c2ddf4803888
- Degrees
- Convert an angle specified in radians to degrees
- f53628df-d187-47f6-8939-9a7cff89ea30
- Degrees
- Deg
-
764
997
64
28
-
794
1011
- Angle in radians
- 6e9d9246-ea82-40e7-a5c7-6200a0750140
- Radians
- R
- false
- 619887fe-9427-4cea-b7fd-0b8e37ad0966
- 1
-
766
999
13
24
-
774
1011
- Angle in degrees
- 1487d807-5f9b-4abc-9b8d-effa22608b5d
- Degrees
- D
- false
- 0
-
809
999
17
24
-
817.5
1011
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- f1c497f2-a656-46bd-97ff-e6f55517ad83
- Construct Point
- Pt
-
390
743
67
64
-
421
775
- {x} coordinate
- f274b47b-1218-4782-8247-527101e3221f
- X coordinate
- X
- false
- 0
-
392
745
14
20
-
400.5
755
- 1
- 1
- {0}
- 0
- {y} coordinate
- 8bb61e7c-9fbb-42a5-be49-c22980dcde8c
- Y coordinate
- Y
- false
- fd7d6e04-d8e1-46ec-9660-5d3b6392bb5c
- 1
-
392
765
14
20
-
400.5
775
- 1
- 1
- {0}
- -100
- {z} coordinate
- fd7813a9-1054-41ca-9f6b-83a5fd0efcce
- Z coordinate
- Z
- false
- 0
-
392
785
14
20
-
400.5
795
- 1
- 1
- {0}
- 0
- Point coordinate
- 544607c8-b250-4465-bd1a-e6ed510b2090
- Point
- Pt
- false
- 0
-
436
745
19
60
-
445.5
775
- d5967b9f-e8ee-436b-a8ad-29fdcecf32d5
- Curve
- Contains a collection of generic curves
- 12b4fe3c-7f43-444b-be77-19b89104763b
- Curve
- Crv
- false
- 9cf1549b-e355-4e34-8c66-56776a6693a3
- 1
-
784
825
50
24
-
809.8876
837.7669
- 17b7152b-d30d-4d50-b9ef-c9fe25576fc2
- XY Plane
- World XY plane.
- true
- 8cd68a99-5c0c-40f6-8f6c-c57b65a7c0fb
- XY Plane
- XY
-
492
837
64
28
-
523
851
- Origin of plane
- d599495e-da0d-4b5f-96ca-d429779f4f7e
- Origin
- O
- false
- 544607c8-b250-4465-bd1a-e6ed510b2090
- 1
-
494
839
14
24
-
502.5
851
- 1
- 1
- {0}
-
0
0
0
- World XY plane
- 2e367eec-73c9-49fe-931b-de57feb15198
- Plane
- P
- false
- 0
-
538
839
16
24
-
546
851
- a4cd2751-414d-42ec-8916-476ebf62d7fe
- Radians
- Convert an angle specified in degrees to radians
- 0de50cbe-99d5-4598-bc61-8cc3eacb616f
- Radians
- Rad
-
481
954
64
28
-
512
968
- Angle in degrees
- 8514650b-5a4b-4bd4-b272-4db0089c786a
- Degrees
- D
- false
- 5eda29cf-b445-43dc-9fe0-d002172bab75
- 1
-
483
956
14
24
-
491.5
968
- Angle in radians
- b2a8f43d-df9e-4385-bfbe-4e7a54acdc52
- Radians
- R
- false
- 0
-
527
956
16
24
-
535
968
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 5eda29cf-b445-43dc-9fe0-d002172bab75
- Number Slider
- angle °
- false
- 0
-
167
960
295
20
-
167.2024
960.4379
- 2
- 1
- 0
- 170
- 0
- 0
- 60
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- e59fa8de-3b01-40cb-9090-35007fc19bba
- Panel
- false
- 0
- 03e53700-d1d7-480a-9312-c1af517baedd
- 1
- Double click to edit panel content…
-
739
877
97
38
- 0
- 0
- 0
-
739.8782
877.1644
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 552a2357-924c-4919-bc11-da8244c7b3c6
- Panel
- false
- 0
- 09f794fe-078e-4e7b-840b-9d52b913b097
- 1
- Double click to edit panel content…
-
850
902
105
55
- 0
- 0
- 0
-
850.7964
902.0322
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 7d007978-016f-4867-9bef-68c359c70508
- Panel
- false
- 0
- 2373426a-a151-4361-9f8e-d19fef664dc8
- 1
- Double click to edit panel content…
-
738
937
97
38
- 0
- 0
- 0
-
738.8221
937.5484
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 6f2330d2-0e46-4e09-9ac5-7b7d2a1d3954
- Panel
- false
- 0
- 0
- 0.5
-
988
843
50
20
- 0
- 0
- 0
-
988.351
843.602
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- fd7d6e04-d8e1-46ec-9660-5d3b6392bb5c
- Panel
- false
- 0
- 0
- -100
-
312
766
50
20
- 0
- 0
- 0
-
312.841
766.482
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 8cc3a196-f6a0-49ea-9ed9-0cb343a3ae64
- XZ Plane
- World XZ plane.
- true
- 8b551e34-6c38-4a2b-9e47-c0b841fb2d47
- XZ Plane
- XZ
-
1145
713
64
28
-
1176
727
- Origin of plane
- 6e5d1c51-960b-46f9-898e-f2b11bdb8846
- Origin
- O
- false
- 544607c8-b250-4465-bd1a-e6ed510b2090
- 1
-
1147
715
14
24
-
1155.5
727
- 1
- 1
- {0}
-
0
0
0
- World XZ plane
- 0654eb92-001e-43e0-b38a-58a5d0d80f8e
- Plane
- P
- false
- 0
-
1191
715
16
24
-
1199
727
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 95f9fd7f-37dc-4bd8-8105-7301ef052bdd
- Panel
- false
- 0
- 0
- 160
-
306
175
50
20
- 0
- 0
- 0
-
306.7406
175.2052
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
-552.3402
73.81226
-
-194.0922
73.81226
-
-194.0922
88.8396
-
-552.3402
88.8396
- A quick note
- Microsoft Sans Serif
- 501dc92a-f2db-4bb4-8054-89bd8827333b
- false
- Scribble
- Scribble
- 16
- for testing different points on an alternate plane
-
-557.3402
68.81226
368.248
25.02734
-
-552.3402
73.81226
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
317.6904
47.65552
-
768.3664
47.65552
-
768.3664
71.13574
-
317.6904
71.13574
- A quick note
- Microsoft Sans Serif
- 32f0e79e-6dca-4f24-9b30-17ca99e1ac07
- false
- Scribble
- Scribble
- 25
- Elastic Bending Script - Main Example
-
312.6904
42.65552
460.676
33.48022
-
317.6904
47.65552
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
559.8143
683.617
-
913.3091
683.2137
-
913.3262
698.241
-
559.8313
698.6443
- A quick note
- Microsoft Sans Serif
- 834f8190-7e8f-4039-8f4f-5e398c86ddfa
- false
- Scribble
- Scribble
- 16
- At 60°, minimum curve radius = height. Try 90°
-
554.8143
678.2137
363.5119
25.43066
-
559.8143
683.617
- 079bd9bd-54a0-41d4-98af-db999015f63d
- VB Script
- Private Function IsSet(ByVal param As String) As Boolean ' Check if an input parameter has data
Dim i As Integer = Component.Params.IndexOfInputParam(param)
If i > -1 Then
Return Component.Params.Input.ElementAt(i).DataType > 1 ' input parameter DataType of 1 means it's not receiving input (internal or external)
Else
Msg("error", "Input parameter '" & param & "' not found")
Return False
End If
End Function
Private Sub Msg(ByVal type As String, ByVal msg As String) ' Output an error, warning, or informational message
Select Case type
Case "error"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, msg)
Print("Error: " & msg)
Case "warning"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, msg)
Print("Warning: " & msg)
Case "info"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, msg)
Print(msg)
End Select
End Sub
' Solve for the m parameter from length and width (reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m))
Private Function SolveMFromLenWid(ByVal L As Double, ByVal w As Double) As Double
If w = 0 Then
Return Defined.M_ZERO_W ' for the boundry condition width = 0, bypass the function and return the known m value
End If
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwl As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwl = 2 * EllipticE(m) / EllipticK(m) - 1 ' calculate w/L with the test value of m
If cwl < w / L Then ' compares the calculated w/L with the actual w/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Solve for the m parameter from length and height (reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m))
' Note that it's actually possible to find 2 valid values for m (hence 2 width values) at certain height values
Private Function SolveMFromLenHt(ByVal L As Double, ByVal h As Double) As List(Of Double)
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim twoWidths As Boolean = h / L >= Defined.DOUBLE_W_HL_RATIO And h / L < Defined.MAX_HL_RATIO ' check to see if h/L is within the range where 2 solutions for the width are possible
Dim m As Double
Dim mult_m As New List(Of Double)
Dim chl As Double
If twoWidths Then
' find the first of two possible solutions for m with the following limits:
lower = Defined.M_DOUBLE_W ' see constants at bottom of script
upper = Defined.M_MAXHEIGHT ' see constants at bottom of script
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
' then find the second of two possible solutions for m with the following limits:
lower = Defined.M_MAXHEIGHT ' see constants at bottom of script
upper = 1
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl < h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
If m <= Defined.M_MAX Then ' return this m parameter only if it falls within the maximum useful value (above which the curve breaks down)
mult_m.Add(m)
End If
Else
' find the one possible solution for the m parameter
upper = Defined.M_DOUBLE_W ' limit the upper end of the search to the maximum value of m for which only one solution exists
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
End If
Return mult_m
End Function
' Solve for the m parameter from width and height (derived from reference {1} equations (33) and (34) with same notes as above)
Private Function SolveMFromWidHt(ByVal w As Double, ByVal h As Double) As Double
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwh As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwh = (2 * EllipticE(m) - EllipticK(m)) / Math.Sqrt(m) ' calculate w/h with the test value of m
If cwh < w / h Then ' compares the calculated w/h with the actual w/h then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Calculate length based on height and an m parameter, derived from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_L(ByVal h As Double, ByVal m As Double) As Double
Return h * EllipticK(m) / Math.Sqrt(m)
End Function
' Calculate width based on length and an m parameter, derived from reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m)
Private Function Cal_W(ByVal L As Double, ByVal m As Double) As Double
Return L * (2 * EllipticE(m) / EllipticK(m) - 1)
End Function
' Calculate height based on length and an m parameter, from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_H(ByVal L As Double, ByVal m As Double) As Double
Return L * Math.Sqrt(m) / EllipticK(m)
End Function
' Calculate the unique m parameter based on a start tangent angle, from reference {2}, just above equation (9a), that states k = Sin(angle / 2 + Pi / 4),
' but as m = k^2 and due to this script's need for an angle rotated 90° versus the one in reference {1}, the following formula is the result
' New note: verified by reference {4}, pg. 78 at the bottom
Private Function Cal_M(ByVal a As Double) As Double
Return (1 - Math.Cos(a)) / 2 ' equal to Sin^2(a/2) too
End Function
' Calculate start tangent angle based on an m parameter, derived from above formula
Private Function Cal_A(ByVal m As Double) As Double
Return Math.Acos(1 - 2 * m)
End Function
' This is the heart of this script, taking the found (or specified) length, width, and angle values along with the found m parameter to create
' a list of points that approximate the shape or form of the elastica. It works by finding the x and y coordinates (which are reversed versus
' the original equations (12a) and (12b) from reference {2} due to the 90° difference in orientation) based on the tangent angle along the curve.
' See reference {2} for more details on how they derived it. Note that to simplify things, the algorithm only calculates the points for half of the
' curve, then mirrors those points along the y-axis.
Private Function FindBendForm(ByVal L As Double, ByVal w As Double, ByVal m As Double, ByVal ang As Double, ByVal refPln As Plane) As List(Of Point3d)
L = L / 2 ' because the below algorithm is based on the formulas in reference {2} for only half of the curve
w = w / 2 ' same
If ang = 0 Then ' if angle (and height) = 0, then simply return the start and end points of the straight line
Dim out As New List(Of Point3d)
out.Add(refPln.PointAt(w, 0, 0))
out.Add(refPln.PointAt(-w, 0, 0))
Return out
End If
Dim x As Double
Dim y As Double
Dim halfCurvePts As New List(Of Point3d)
Dim fullCurvePts As New List(Of Point3d)
Dim translatedPts As New List(Of Point3d)
ang -= Math.PI / 2 ' a hack to allow this algorithm to work, since the original curve in paper {2} was rotated 90°
Dim angB As Double = ang + (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' angB is the 'lowercase theta' which should be in formula {2}(12b) as the interval
' start [a typo...see equation(3)]. It's necessary to start angB at ang + [interval] instead of just ang due to integration failing at angB = ang
halfCurvePts.Add(New Point3d(w, 0, 0)) ' start with this known initial point, as integration will fail when angB = ang
' each point {x, y} is calculated from the tangent angle, angB, that occurs at each point (which is why this iterates from ~ang to -pi/2, the known end condition)
Do While Math.Round(angB, Defined.ROUNDTO) >= Math.Round(-Math.PI / 2, Defined.ROUNDTO)
y = (Math.Sqrt(2) * Math.Sqrt(Math.Sin(ang) - Math.Sin(angB)) * (w + L)) / (2 * EllipticE(m)) ' note that x and y are swapped vs. (12a) and (12b)
x = (L / (Math.Sqrt(2) * EllipticK(m))) * Simpson(angB, -Math.PI / 2, 500, ang) ' calculate the Simpson approximation of the integral (function f below)
' over the interval angB ('lowercase theta') to -pi/2. side note: is 500 too few iterations for the Simson algorithm?
If Math.Round(x, Defined.ROUNDTO) = 0 Then x = 0
halfCurvePts.Add(New Point3d(x, y, 0))
angB += (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' onto the next tangent angle
Loop
' After finding the x and y values for half of the curve, add the {-x, y} values for the rest of the curve
For Each point As Point3d In halfCurvePts
If Math.Round(point.X, Defined.ROUNDTO) = 0 Then
If Math.Round(point.Y, Defined.ROUNDTO) = 0 Then
fullCurvePts.Add(New Point3d(0, 0, 0)) ' special case when width = 0: when x = 0, only duplicate the point when y = 0 too
End If
Else
fullCurvePts.Add(New Point3d(-point.X, point.Y, 0))
End If
Next
halfCurvePts.Reverse
fullCurvePts.AddRange(halfCurvePts)
For Each p As Point3d In fullCurvePts
translatedPts.Add(refPln.PointAt(p.X, p.Y, p.Z)) ' translate the points from the reference plane to the world plane
Next
Return translatedPts
End Function
' Interpolates the points from FindBendForm to create the Elastica curve. Uses start & end tangents for greater accuracy.
Private Function MakeCurve(ByVal pts As List(Of Point3d), ByVal ang As Double, ByVal refPln As Plane) As Curve
If ang <> 0 Then
Dim ts, te As New Vector3d(refPln.XAxis)
ts.Rotate(ang, refPln.ZAxis)
te.Rotate(-ang, refPln.ZAxis)
Return Curve.CreateInterpolatedCurve(pts, 3, CurveKnotStyle.Chord, ts, te) ' 3rd degree curve with 'Chord' Knot Style
Else
Return Curve.CreateInterpolatedCurve(pts, 3) ' if angle (and height) = 0, then simply interpolate the straight line (no start/end tangents)
End If
End Function
' Implements the Simpson approximation for an integral of function f below
Public Function Simpson(a As Double, b As Double, n As Integer, theta As Double) As Double 'n should be an even number
Dim j As Integer, s1 As Double, s2 As Double, h As Double
h = (b - a) / n
s1 = 0
s2 = 0
For j = 1 To n - 1 Step 2
s1 = s1 + fn(a + j * h, theta)
Next j
For j = 2 To n - 2 Step 2
s2 = s2 + fn(a + j * h, theta)
Next j
Simpson = h / 3 * (fn(a, theta) + 4 * s1 + 2 * s2 + fn(b, theta))
End Function
' Specific calculation for the above integration
Public Function fn(x As Double, theta As Double) As Double
fn = Math.Sin(x) / (Math.Sqrt(Math.Sin(theta) - Math.Sin(x))) ' from reference {2} formula (12b)
End Function
' Return the Complete Elliptic integral of the 1st kind
' Abramowitz and Stegun p.591, formula 17.3.11
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticK(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum += Math.Pow(m, i) * Math.Pow(term, 2)
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
' Return the Complete Elliptic integral of the 2nd kind
' Abramowitz and Stegun p.591, formula 17.3.12
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticE(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum -= Math.Pow(m, i) * Math.Pow(term, 2) / above
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
Friend Partial NotInheritable Class Defined
Private Sub New()
End Sub
' Note: most of these values for m and h/L ratio were found with Wolfram Alpha and either specific intercepts (x=0) or local minima/maxima. They should be constant.
Public Const M_SKETCHY As Double = 0.95 ' value of the m parameter where the curvature near the ends of the curve gets wonky
Public Const M_MAX As Double = 0.993 ' maximum useful value of the m parameter, above which this algorithm for the form of the curve breaks down
Public Const M_ZERO_W As Double = 0.826114765984970336 ' value of the m parameter when width = 0
Public Const M_MAXHEIGHT As Double = 0.701327460663101223 ' value of the m parameter at maximum possible height of the bent rod/wire
Public Const M_DOUBLE_W As Double = 0.180254422335013983 ' minimum value of the m parameter when two width values are possible for a given height and length
Public Const DOUBLE_W_HL_RATIO As Double = 0.257342117984635757 ' value of the height/length ratio above which there are two possible width values
Public Const MAX_HL_RATIO As Double = 0.403140189705650243 ' maximum possible value of the height/length ratio
Public Const MAXERR As Double = 0.0000000001 ' error tolerance
Public Const MAXIT As Integer = 100 ' maximum number of iterations
Public Const ROUNDTO As Integer = 10 ' number of decimal places to round off to
Public Const CURVEDIVS As Integer = 50 ' number of sample points for building the curve (or half-curve as it were)
End Class
- A VB.NET scriptable component
-
98
86
- true
- bf1f4616-5fd9-426e-9474-52a076d17bf4
- VB Script
- VB
- true
- 0
- ' -----------------------------------------------------------------
' Elastic Bending Script by Will McElwain
' Created February 2014
'
' DESCRIPTION:
' This beast creates the so-called 'elastica curve', the shape a long, thin rod or wire makes when it is bent elastically (i.e. not permanently). In this case, force
' is assumed to only be applied horizontally (which would be in line with the rod at rest) and both ends are assumed to be pinned or hinged meaning they are free
' to rotate (as opposed to clamped, when the end tangent angle is fixed, usually horizontally). An interesting finding is that it doesn't matter what the material or
' cross-sectional area is, as long as they're uniform along the entire length. Everything makes the same shape when bent as long as it doesn't cross the threshold
' from elastic to plastic (permanent) deformation (I don't bother to find that limit here, but can be found if the yield stress for a material is known).
'
' Key to the formulas used in this script are elliptic integrals, specifically K(m), the complete elliptic integral of the first kind, and E(m), the complete elliptic
' integral of the second kind. There was a lot of confusion over the 'm' and 'k' parameters for these functions, as some people use them interchangeably, but they are
' not the same. m = k^2 (thus k = Sqrt(m)). I try to use the 'm' parameter exclusively to avoid this confusion. Note that there is a unique 'm' parameter for every
' configuration/shape of the elastica curve.
'
' This script tries to find that unique 'm' parameter based on the inputs. The algorithm starts with a test version of m, evaluates an expression, say 2*E(m)/K(m)-1,
' then compares the result to what it should be (in this case, a known width/length ratio). Iterate until the correct m is found. Once we have m, we can then calculate
' all of the other unknowns, then find points that lie on that curve, then interpolate those points for the actual curve. You can also use Wolfram|Alpha as I did to
' find the m parameter based on the equations in this script (example here: http://tiny.cc/t4tpbx for when say width=45.2 and length=67.1).
'
' Other notes:
' * This script works with negative values for width, which will creat a self-intersecting curve (as it should). The curvature of the elastica starts to break down around
' m=0.95 (~154°), but this script will continue to work until M_MAX, m=0.993 (~169°). If you wish to ignore self-intersecting curves, set ignoreSelfIntersecting to True
' * When the only known values are length and height, it is actually possible for certain ratios of height to length to have two valid m values (thus 2 possible widths
' and angles). This script will return them both.
' * Only the first two valid parameters (of the required ones) will be used, meaning if all four are connected (length, width or a PtB, height, and angle), this script will
' only use length and width (or a PtB).
' * Depending on the magnitude of your inputs (say if they're really small, like if length < 10), you might have to increase the constant ROUNDTO at the bottom
'
' REFERENCES:
' {1} "The elastic rod" by M.E. Pacheco Q. & E. Pina, http://www.scielo.org.mx/pdf/rmfe/v53n2/v53n2a8.pdf
' {2} "An experiment in nonlinear beam theory" by A. Valiente, http://www.deepdyve.com/lp/doc/I3lwnxdfGz , also here: http://tiny.cc/Valiente_AEiNBT
' {3} "Snap buckling, writhing and Loop formation In twisted rods" by V.G.A. GOSS, http://myweb.lsbu.ac.uk/~gossga/thesisFinal.pdf
' {4} "Theory of Elastic Stability" by Stephen Timoshenko, http://www.scribd.com/doc/50402462/Timoshenko-Theory-of-Elastic-Stability (start on p. 76)
'
' INPUT:
' PtA - First anchor point (required)
' PtB - Second anchor point (optional, though 2 out of the 4--length, width, height, angle--need to be specified)
' [note that PtB can be the same as PtA (meaning width would be zero)]
' [also note that if a different width is additionally specified that's not equal to the distance between PtA and PtB, then the end point will not equal PtB anymore]
' Pln - Plane of the bent rod/wire, which bends up in the +y direction. The line between PtA and PtB (if specified) must be parallel to the x-axis of this plane
'
' ** 2 of the following 4 need to be specified **
' Len - Length of the rod/wire, which needs to be > 0
' Wid - Width between the endpoints of the curve [note: if PtB is specified in addition, and distance between PtA and PtB <> width, the end point will be relocated
' Ht - Height of the bent rod/wire (when negative, curve will bend downward, relative to the input plane, instead)
' Ang - Inner departure angle or tangent angle (in radians) at the ends of the bent rod/wire. Set up so as width approaches length (thus height approaches zero), angle approaches zero
'
' * Following variables only needed for optional calculating of bending force, not for shape of curve.
' E - Young's modulus (modulus of elasticity) in GPa (=N/m^2) (material-specific. for example, 7075 aluminum is roughly 71.7 GPa)
' I - Second moment of area (or area moment of inertia) in m^4 (cross-section-specific. for example, a hollow rod
' would have I = pi * (outer_diameter^4 - inner_diameter^4) / 32
' Note: E*I is also known as flexural rigidity or bending stiffness
'
' OUTPUT:
' out - only for debugging messages
' Pts - the list of points that approximate the shape of the elastica
' Crv - the 3rd-degree curve interpolated from those points (with accurate start & end tangents)
' L - the length of the rod/wire
' W - the distance (width) between the endpoints of the rod/wire
' H - the height of the bent rod/wire
' A - the tangent angle at the (start) end of the rod/wire
' F - the force needed to hold the rod/wire in a specific shape (based on the material properties & cross-section) **be sure your units for 'I' match your units for the
' rest of your inputs (length, width, etc.). Also note that the critical buckling load (force) that makes the rod/wire start to bend can be found at height=0
'
' THANKS TO:
' Mårten Nettelbladt (thegeometryofbending.blogspot.com)
' Daniel Piker (Kangaroo plugin)
' David Rutten (Grasshopper guru)
' Euler & Bernoulli (the O.G.'s)
'
' -----------------------------------------------------------------
Dim ignoreSelfIntersecting As Boolean = False ' set to True if you don't want to output curves where width < 0, which creates a self-intersecting curve
Dim inCt As Integer = 0 ' count the number of required parameters that are receiving data
Dim length As Double
Dim width As System.Object = Nothing ' need to set as Nothing so we can check if it has been assigned a value later
Dim height As Double
Dim angle As Double
Dim m As Double
Dim multiple_m As New List(Of Double)
Dim AtoB As Line
Dim flip_H As Boolean = False ' if height is negative, this flag will be set
Dim flip_A As Boolean = False ' if angle is negative, this flag will be set
If Not IsSet("Pln") Then
Msg("error", "Base plane is not set")
Return
End If
If Not IsSet("PtA") Then
Msg("error", "Point A is not set")
Return
End If
If Math.Round(Pln.DistanceTo(PtA), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point A is not on the base plane")
Return
End If
Dim refPlane As Plane = Pln ' create a reference plane = input plane and set the origin of it to PtA in case PtA isn't the origin already
refPlane.Origin = PtA
If IsSet("PtB") Then
If Math.Round(Pln.DistanceTo(PtB), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point B is not on the base plane")
Return
End If
AtoB = New Line(PtA, PtB)
If AtoB.Length <> 0 And Not AtoB.Direction.IsPerpendicularTo(Pln.YAxis) Then
Msg("error", "The line between PtA and PtB is not perpendicular to the Y-axis of the specified plane")
Return
End If
inCt += 1
If IsSet("Wid") Then Msg("info", "Wid will override the distance between PtA and PtB. If you do not want this to happen, disconnect PtB or Wid.")
width = PtA.DistanceTo(PtB) ' get the width (distance) between PtA and PtB
Dim refPtB As Point3d
refPlane.RemapToPlaneSpace(PtB, refPtB)
If refPtB.X < 0 Then width = -width ' check if PtB is to the left of PtA...if so, width is negative
End If
If IsSet("Len") Then inCt += 1
If IsSet("Wid") Then inCt += 1
If IsSet("Ht") Then inCt += 1
If IsSet("Ang") Then inCt += 1
If inCt > 2 Then Msg("info", "More parameters set than are required (out of length, width, height, angle). Only using the first two valid ones.")
' check for connected/specified inputs. note: only the first two that it comes across will be used
If IsSet("Len") Then ' if length is specified then...
If Len <= 0 Then
Msg("error", "Length cannot be negative or zero")
Return
End If
If IsSet("Wid") Then ' find height & angle based on length and specified width
If Wid > Len Then
Msg("error", "Width is greater than length")
Return
End If
If Wid = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
width = Wid
Else
m = SolveMFromLenWid(Len, Wid)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
width = Wid
End If
Else If width IsNot Nothing Then ' find height & angle based on length and calculated width (distance between PtA and PtB)
If width > Len Then
Msg("error", "Width is greater than length")
Return
End If
If width = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
Else
m = SolveMFromLenWid(Len, width)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
Else If IsSet("Ht") Then ' find width & angle based on length and height ** possible to return 2 results **
If Math.Abs(Ht / Len) > Defined.MAX_HL_RATIO Then
Msg("error", "Height not possible with given length")
Return
End If
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
width = Len
angle = 0
Else
multiple_m = SolveMFromLenHt(Len, Ht) ' note that it's possible for two values of m to be found if height is close to max height
If multiple_m.Count = 1 Then ' if there's only one m value returned, calculate the width & angle here. we'll deal with multiple m values later
m = multiple_m.Item(0)
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
End If
height = Ht
Else If IsSet("Ang") Then ' find width & height based on length and angle
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
width = Len
height = 0
Else
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to length")
Return
End If
length = Len
Else If IsSet("Wid") Then ' if width is specified then...
If IsSet("Ht") Then ' find length & angle based on specified width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = Wid
angle = 0
Else
m = SolveMFromWidHt(Wid, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on specified width and angle
If Wid = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = Wid
height = 0
Else
length = Wid / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to width (Wid)")
Return
End If
width = Wid
Else If width IsNot Nothing Then ' if width is determined by PtA and PtB then...
If IsSet("Ht") Then ' find length & angle based on calculated width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = width
angle = 0
Else
m = SolveMFromWidHt(width, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on calculated width and angle
If width = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = width
height = 0
Else
length = width / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to PtA and PtB")
Return
End If
Else If IsSet("Ht") Then ' if height is specified then...
If IsSet("Ang") Then ' find length & width based on height and angle
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_H = True
flip_A = True
End If
If Ht = 0 Then
Msg("error", "Height can't = 0 if only height and angle are specified")
Return
Else
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = Not flip_A
flip_H = Not flip_H
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then
Msg("error", "Angle can't = 0 if only height and angle are specified")
Return
Else
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
width = Cal_W(length, m) ' L * (2 * E(m) / K(m) - 1)
End If
angle = Ang
End If
height = Ht
Else
Msg("error", "Need to specify one more parameter in addition to height")
Return
End If
Else If IsSet("Ang") Then
Msg("error", "Need to specify one more parameter in addition to angle")
Return
Else
Msg("error", "Need to specify two of the four parameters: length, width (or PtB), height, and angle")
Return
End If
If m > Defined.M_MAX Then
Msg("error", "Form of curve not solvable with current algorithm and given inputs")
Return
End If
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
If multiple_m.Count > 1 Then ' if there is more than one m value returned, calculate the width, angle, and curve for each
Dim multi_pts As New DataTree(Of Point3d)
Dim multi_crv As New List(Of Curve)
Dim tmp_pts As New List(Of Point3d)
Dim multi_W, multi_A, multi_F As New List(Of Double)
Dim j As Integer = 0 ' used for creating a new branch (GH_Path) for storing pts which is itself a list of points
For Each m_val As Double In multiple_m
width = Cal_W(length, m_val) 'length * (2 * EllipticE(m_val) / EllipticK(m_val) - 1)
If width < 0 And ignoreSelfIntersecting Then
Msg("warning", "One curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Continue For
End If
If m_val >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve whose width = " & Math.Round(width, 4) & " is not guaranteed")
angle = Cal_A(m_val) 'Math.Asin(2 * m_val - 1)
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
tmp_pts = FindBendForm(length, width, m_val, angle, refPlane)
multi_pts.AddRange(tmp_pts, New GH_Path(j))
multi_crv.Add(MakeCurve(tmp_pts, angle, refPlane))
multi_W.Add(width)
If flip_A Then angle = -angle
multi_A.Add(angle)
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
multi_F.Add(EllipticK(m_val) ^ 2 * E * I / length ^ 2) ' from reference {4} pg. 79
j += 1
refPlane.Origin = PtA ' reset the reference plane origin to PtA for the next m_val
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m_val & ", k=" & Math.Sqrt(m_val) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
Next
' assign the outputs
Pts = multi_pts
Crv = multi_crv
L = length
W = multi_W
If flip_H Then height = -height
H = height
A = multi_A
F = multi_F
Else ' only deal with the single m value
If m >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve at these parameters is not guaranteed")
If width < 0 And ignoreSelfIntersecting Then
Msg("error", "Curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Return
End If
Pts = FindBendForm(length, width, m, angle, refPlane)
Crv = MakeCurve(pts, angle, refPlane)
L = length
W = width
If flip_H Then height = -height
H = height
If flip_A Then angle = -angle
A = angle
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
F = EllipticK(m) ^ 2 * E * I / length ^ 2 ' from reference {4} pg. 79. Note: the critical buckling (that makes the rod/wire start to bend) can be found at height=0 (width=length)
'height = Math.Sqrt(((2 * Len / 5) ^ 2 - ((Wid - Len / 5) / 2) ^ 2) ' quick approximation discovered by Mårten of 'Geometry of Bending' fame ( http://tiny.cc/it2pbx )
'width = (Len +/- 2 * Math.Sqrt(4 * Len ^ 2 - 25 * Ht ^ 2)) / 5 ' derived from above
'length = (2 * Math.Sqrt(15 * Ht ^ 2 + 4 * Wid ^ 2) - Wid) / 3 ' derived from above
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m & ", k=" & Math.Sqrt(m) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
End If
-
618
1502
84
184
-
660
1594
- 9
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 8
- 3ede854e-c753-40eb-84cb-b48008f14fd4
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- true
- Script Variable PtA
- fc00bec5-e331-4012-b0a8-a6f9d0f686f7
- PtA
- PtA
- true
- 0
- true
- 7470aaae-fe5c-4a6e-a5d7-3c8c950bb9fb
- 1
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
620
1504
25
20
-
634
1514
- true
- Script Variable PtB
- c5bc96c5-9e28-4cb8-9259-356c9db2b9fb
- PtB
- PtB
- true
- 0
- true
- 0
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
620
1524
25
20
-
634
1534
- true
- Script Variable Pln
- 71f32d80-b186-4e03-b761-b9bb960ea743
- Pln
- Pln
- true
- 0
- true
- c7f844d2-ba5e-476f-b4d4-193dcea7a216
- 1
- 3897522d-58e9-4d60-b38c-978ddacfedd8
-
620
1544
25
20
-
634
1554
- true
- Script Variable Len
- 0aa34a2c-a64a-42a7-9ee2-ff1e67f56177
- Len
- Len
- true
- 0
- true
- 7d11a12d-1f6f-4777-9bc7-965dd3035809
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
620
1564
25
20
-
634
1574
- true
- Script Variable Wid
- 1af65384-240e-46e3-8309-6fc1ae7504d7
- Wid
- Wid
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
620
1584
25
20
-
634
1594
- true
- Script Variable Ht
- 8d0b03a7-827e-4902-8b4f-5bb0e815b41b
- Ht
- Ht
- true
- 0
- true
- d1327bed-c875-4acd-82dd-5fed4b45b311
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
620
1604
25
20
-
634
1614
- true
- Script Variable Ang
- 2deaf321-2e08-44e8-a80f-9628891997a5
- Ang
- Ang
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
620
1624
25
20
-
634
1634
- true
- Script Variable E
- 8dff382d-9d65-40bc-ac45-64afb28a006d
- E
- E
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
620
1644
25
20
-
634
1654
- true
- Script Variable I
- 33d1c654-7377-4887-9445-52cefe06021d
- I
- I
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
620
1664
25
20
-
634
1674
- 1
- Print, Reflect and Error streams
- 964ae01d-510e-42cb-b06f-38805376764d
- out
- out
- false
- 0
-
675
1504
25
22
-
687.5
1515.25
- Output parameter Pts
- 17f99969-6a6b-431e-8210-f6e15df9a9af
- Pts
- Pts
- false
- 0
-
675
1526
25
23
-
687.5
1537.75
- Output parameter Crv
- 6548d62a-dfa5-4478-9f16-8d4fb96732c9
- Crv
- Crv
- false
- 0
-
675
1549
25
22
-
687.5
1560.25
- Output parameter L
- a2a9f9ae-744d-4886-a3ee-4c33b8365028
- L
- L
- false
- 0
-
675
1571
25
23
-
687.5
1582.75
- Output parameter W
- 0c900729-ed6e-40e8-809f-e2432521ac54
- W
- W
- false
- 0
-
675
1594
25
22
-
687.5
1605.25
- Output parameter H
- 7772d1f7-9786-4d55-8690-af9d6877a777
- H
- H
- false
- 0
-
675
1616
25
23
-
687.5
1627.75
- Output parameter A
- bc883717-6d8a-41a6-bb0b-3d7c5d7a61ea
- A
- A
- false
- 0
-
675
1639
25
22
-
687.5
1650.25
- Output parameter F
- fc8245e0-b2d0-471d-9254-01a0eff7a0b4
- F
- F
- false
- 0
-
675
1661
25
23
-
687.5
1672.75
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 7d11a12d-1f6f-4777-9bc7-965dd3035809
- Number Slider
- length
- false
- 0
-
163
1555
382
20
-
163.9633
1555.108
- 2
- 1
- 0
- 400
- 0
- 0
- 225
- fbac3e32-f100-4292-8692-77240a42fd1a
- Point
- Contains a collection of three-dimensional points
- true
- 108e145a-a9f8-4c1a-856f-eef3be9eef4b
- Point
- Pt
- false
- 17f99969-6a6b-431e-8210-f6e15df9a9af
- 1
-
788
1463
50
24
-
813.4178
1475.827
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- de6e3b3a-9675-45ae-ad2f-bfc0988f9582
- Panel
- false
- 0
- a0d9174c-2b33-4845-86da-70d722e564b7
- 1
- Double click to edit panel content…
-
846
1678
105
55
- 0
- 0
- 0
-
846.2736
1678.188
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 0d77c51e-584f-44e8-aed2-c2ddf4803888
- Degrees
- Convert an angle specified in radians to degrees
- 9bc218b0-faa5-4566-a292-b5565b343ee8
- Degrees
- Deg
-
759
1690
64
28
-
789
1704
- Angle in radians
- 8dd5ffda-e6b3-4328-a1c1-726386b31dd7
- Radians
- R
- false
- bc883717-6d8a-41a6-bb0b-3d7c5d7a61ea
- 1
-
761
1692
13
24
-
769
1704
- Angle in degrees
- a0d9174c-2b33-4845-86da-70d722e564b7
- Degrees
- D
- false
- 0
-
804
1692
17
24
-
812.5
1704
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- 5bb8544d-21ed-430d-b9a1-3d097d9c0f85
- Construct Point
- Pt
-
474
1440
67
64
-
505
1472
- {x} coordinate
- fd05bf19-e5b9-428a-a0b7-1183ddb4d4cb
- X coordinate
- X
- false
- 18da725f-8fce-4b5c-bfc0-b35f534747f4
- 1
-
476
1442
14
20
-
484.5
1452
- 1
- 1
- {0}
- 0
- {y} coordinate
- 5d500e04-4c0a-4e2e-90e3-a69f12e6e56b
- Y coordinate
- Y
- false
- bdda70a3-abe5-47d3-bab1-d54eaac87273
- 1
-
476
1462
14
20
-
484.5
1472
- 1
- 1
- {0}
- 0
- {z} coordinate
- b73aa23e-da5e-429b-a2ad-c29573433d8d
- Z coordinate
- Z
- false
- 0
-
476
1482
14
20
-
484.5
1492
- 1
- 1
- {0}
- 0
- Point coordinate
- 7470aaae-fe5c-4a6e-a5d7-3c8c950bb9fb
- Point
- Pt
- false
- 0
-
520
1442
19
60
-
529.5
1472
- d5967b9f-e8ee-436b-a8ad-29fdcecf32d5
- Curve
- Contains a collection of generic curves
- d707c7a6-ce24-45bb-a3b3-c616b13d07dc
- Curve
- Crv
- false
- 6548d62a-dfa5-4478-9f16-8d4fb96732c9
- 1
-
788
1506
50
24
-
813.4067
1518.357
- 17b7152b-d30d-4d50-b9ef-c9fe25576fc2
- XY Plane
- World XY plane.
- true
- 1653bea2-6780-45be-ad4a-2c29f59e4c19
- XY Plane
- XY
-
479
1515
64
28
-
510
1529
- Origin of plane
- 6ccdcfe2-c623-42d1-8da5-1e99c86f6f52
- Origin
- O
- false
- 0
-
481
1517
14
24
-
489.5
1529
- 1
- 1
- {0}
-
0
0
0
- World XY plane
- c7f844d2-ba5e-476f-b4d4-193dcea7a216
- Plane
- P
- false
- 0
-
525
1517
16
24
-
533
1529
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- d1327bed-c875-4acd-82dd-5fed4b45b311
- Number Slider
- height
- false
- 0
-
168
1608
381
20
-
168.731
1608.997
- 2
- 1
- 0
- 200
- 0
- 0
- 89
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- e3db26aa-60fb-43b8-8092-d7ecfc283153
- Panel
- false
- 0
- a2a9f9ae-744d-4886-a3ee-4c33b8365028
- 1
- Double click to edit panel content…
-
743
1557
97
38
- 0
- 0
- 0
-
743.3972
1557.754
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- dfa914e0-e01f-4bbe-b66d-a9d4a08bb5c7
- Panel
- false
- 0
- 0c900729-ed6e-40e8-809f-e2432521ac54
- 1
- Double click to edit panel content…
-
854
1582
105
55
- 0
- 0
- 0
-
854.3154
1582.622
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- b487f9ab-5cec-404a-9235-d2a5f0e79007
- Panel
- false
- 0
- 7772d1f7-9786-4d55-8690-af9d6877a777
- 1
- Double click to edit panel content…
-
742
1618
97
38
- 0
- 0
- 0
-
742.3411
1618.138
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- bdda70a3-abe5-47d3-bab1-d54eaac87273
- Panel
- false
- 0
- 0
- -150
-
378
1465
50
20
- 0
- 0
- 0
-
378.501
1465.184
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 18da725f-8fce-4b5c-bfc0-b35f534747f4
- Panel
- false
- 0
- 0
- -150
-
377
1434
50
20
- 0
- 0
- 0
-
377.701
1434.784
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
1685.887
79.1758
-
1984.071
81.3421
-
1983.831
114.478
-
1685.647
112.3117
- A quick note
- Microsoft Sans Serif
- 18f8db3f-bb9b-4a79-9d98-1a46a8a0c59b
- false
- Scribble
- Scribble
- 16
- Negative width = self-intersecting result
Negative height and angle work too
-
1680.647
74.1758
308.4244
45.30215
-
1685.887
79.1758
- 079bd9bd-54a0-41d4-98af-db999015f63d
- VB Script
- Private Function IsSet(ByVal param As String) As Boolean ' Check if an input parameter has data
Dim i As Integer = Component.Params.IndexOfInputParam(param)
If i > -1 Then
Return Component.Params.Input.ElementAt(i).DataType > 1 ' input parameter DataType of 1 means it's not receiving input (internal or external)
Else
Msg("error", "Input parameter '" & param & "' not found")
Return False
End If
End Function
Private Sub Msg(ByVal type As String, ByVal msg As String) ' Output an error, warning, or informational message
Select Case type
Case "error"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, msg)
Print("Error: " & msg)
Case "warning"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, msg)
Print("Warning: " & msg)
Case "info"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, msg)
Print(msg)
End Select
End Sub
' Solve for the m parameter from length and width (reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m))
Private Function SolveMFromLenWid(ByVal L As Double, ByVal w As Double) As Double
If w = 0 Then
Return Defined.M_ZERO_W ' for the boundry condition width = 0, bypass the function and return the known m value
End If
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwl As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwl = 2 * EllipticE(m) / EllipticK(m) - 1 ' calculate w/L with the test value of m
If cwl < w / L Then ' compares the calculated w/L with the actual w/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Solve for the m parameter from length and height (reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m))
' Note that it's actually possible to find 2 valid values for m (hence 2 width values) at certain height values
Private Function SolveMFromLenHt(ByVal L As Double, ByVal h As Double) As List(Of Double)
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim twoWidths As Boolean = h / L >= Defined.DOUBLE_W_HL_RATIO And h / L < Defined.MAX_HL_RATIO ' check to see if h/L is within the range where 2 solutions for the width are possible
Dim m As Double
Dim mult_m As New List(Of Double)
Dim chl As Double
If twoWidths Then
' find the first of two possible solutions for m with the following limits:
lower = Defined.M_DOUBLE_W ' see constants at bottom of script
upper = Defined.M_MAXHEIGHT ' see constants at bottom of script
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
' then find the second of two possible solutions for m with the following limits:
lower = Defined.M_MAXHEIGHT ' see constants at bottom of script
upper = 1
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl < h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
If m <= Defined.M_MAX Then ' return this m parameter only if it falls within the maximum useful value (above which the curve breaks down)
mult_m.Add(m)
End If
Else
' find the one possible solution for the m parameter
upper = Defined.M_DOUBLE_W ' limit the upper end of the search to the maximum value of m for which only one solution exists
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
End If
Return mult_m
End Function
' Solve for the m parameter from width and height (derived from reference {1} equations (33) and (34) with same notes as above)
Private Function SolveMFromWidHt(ByVal w As Double, ByVal h As Double) As Double
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwh As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwh = (2 * EllipticE(m) - EllipticK(m)) / Math.Sqrt(m) ' calculate w/h with the test value of m
If cwh < w / h Then ' compares the calculated w/h with the actual w/h then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Calculate length based on height and an m parameter, derived from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_L(ByVal h As Double, ByVal m As Double) As Double
Return h * EllipticK(m) / Math.Sqrt(m)
End Function
' Calculate width based on length and an m parameter, derived from reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m)
Private Function Cal_W(ByVal L As Double, ByVal m As Double) As Double
Return L * (2 * EllipticE(m) / EllipticK(m) - 1)
End Function
' Calculate height based on length and an m parameter, from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_H(ByVal L As Double, ByVal m As Double) As Double
Return L * Math.Sqrt(m) / EllipticK(m)
End Function
' Calculate the unique m parameter based on a start tangent angle, from reference {2}, just above equation (9a), that states k = Sin(angle / 2 + Pi / 4),
' but as m = k^2 and due to this script's need for an angle rotated 90° versus the one in reference {1}, the following formula is the result
' New note: verified by reference {4}, pg. 78 at the bottom
Private Function Cal_M(ByVal a As Double) As Double
Return (1 - Math.Cos(a)) / 2 ' equal to Sin^2(a/2) too
End Function
' Calculate start tangent angle based on an m parameter, derived from above formula
Private Function Cal_A(ByVal m As Double) As Double
Return Math.Acos(1 - 2 * m)
End Function
' This is the heart of this script, taking the found (or specified) length, width, and angle values along with the found m parameter to create
' a list of points that approximate the shape or form of the elastica. It works by finding the x and y coordinates (which are reversed versus
' the original equations (12a) and (12b) from reference {2} due to the 90° difference in orientation) based on the tangent angle along the curve.
' See reference {2} for more details on how they derived it. Note that to simplify things, the algorithm only calculates the points for half of the
' curve, then mirrors those points along the y-axis.
Private Function FindBendForm(ByVal L As Double, ByVal w As Double, ByVal m As Double, ByVal ang As Double, ByVal refPln As Plane) As List(Of Point3d)
L = L / 2 ' because the below algorithm is based on the formulas in reference {2} for only half of the curve
w = w / 2 ' same
If ang = 0 Then ' if angle (and height) = 0, then simply return the start and end points of the straight line
Dim out As New List(Of Point3d)
out.Add(refPln.PointAt(w, 0, 0))
out.Add(refPln.PointAt(-w, 0, 0))
Return out
End If
Dim x As Double
Dim y As Double
Dim halfCurvePts As New List(Of Point3d)
Dim fullCurvePts As New List(Of Point3d)
Dim translatedPts As New List(Of Point3d)
ang -= Math.PI / 2 ' a hack to allow this algorithm to work, since the original curve in paper {2} was rotated 90°
Dim angB As Double = ang + (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' angB is the 'lowercase theta' which should be in formula {2}(12b) as the interval
' start [a typo...see equation(3)]. It's necessary to start angB at ang + [interval] instead of just ang due to integration failing at angB = ang
halfCurvePts.Add(New Point3d(w, 0, 0)) ' start with this known initial point, as integration will fail when angB = ang
' each point {x, y} is calculated from the tangent angle, angB, that occurs at each point (which is why this iterates from ~ang to -pi/2, the known end condition)
Do While Math.Round(angB, Defined.ROUNDTO) >= Math.Round(-Math.PI / 2, Defined.ROUNDTO)
y = (Math.Sqrt(2) * Math.Sqrt(Math.Sin(ang) - Math.Sin(angB)) * (w + L)) / (2 * EllipticE(m)) ' note that x and y are swapped vs. (12a) and (12b)
x = (L / (Math.Sqrt(2) * EllipticK(m))) * Simpson(angB, -Math.PI / 2, 500, ang) ' calculate the Simpson approximation of the integral (function f below)
' over the interval angB ('lowercase theta') to -pi/2. side note: is 500 too few iterations for the Simson algorithm?
If Math.Round(x, Defined.ROUNDTO) = 0 Then x = 0
halfCurvePts.Add(New Point3d(x, y, 0))
angB += (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' onto the next tangent angle
Loop
' After finding the x and y values for half of the curve, add the {-x, y} values for the rest of the curve
For Each point As Point3d In halfCurvePts
If Math.Round(point.X, Defined.ROUNDTO) = 0 Then
If Math.Round(point.Y, Defined.ROUNDTO) = 0 Then
fullCurvePts.Add(New Point3d(0, 0, 0)) ' special case when width = 0: when x = 0, only duplicate the point when y = 0 too
End If
Else
fullCurvePts.Add(New Point3d(-point.X, point.Y, 0))
End If
Next
halfCurvePts.Reverse
fullCurvePts.AddRange(halfCurvePts)
For Each p As Point3d In fullCurvePts
translatedPts.Add(refPln.PointAt(p.X, p.Y, p.Z)) ' translate the points from the reference plane to the world plane
Next
Return translatedPts
End Function
' Interpolates the points from FindBendForm to create the Elastica curve. Uses start & end tangents for greater accuracy.
Private Function MakeCurve(ByVal pts As List(Of Point3d), ByVal ang As Double, ByVal refPln As Plane) As Curve
If ang <> 0 Then
Dim ts, te As New Vector3d(refPln.XAxis)
ts.Rotate(ang, refPln.ZAxis)
te.Rotate(-ang, refPln.ZAxis)
Return Curve.CreateInterpolatedCurve(pts, 3, CurveKnotStyle.Chord, ts, te) ' 3rd degree curve with 'Chord' Knot Style
Else
Return Curve.CreateInterpolatedCurve(pts, 3) ' if angle (and height) = 0, then simply interpolate the straight line (no start/end tangents)
End If
End Function
' Implements the Simpson approximation for an integral of function f below
Public Function Simpson(a As Double, b As Double, n As Integer, theta As Double) As Double 'n should be an even number
Dim j As Integer, s1 As Double, s2 As Double, h As Double
h = (b - a) / n
s1 = 0
s2 = 0
For j = 1 To n - 1 Step 2
s1 = s1 + fn(a + j * h, theta)
Next j
For j = 2 To n - 2 Step 2
s2 = s2 + fn(a + j * h, theta)
Next j
Simpson = h / 3 * (fn(a, theta) + 4 * s1 + 2 * s2 + fn(b, theta))
End Function
' Specific calculation for the above integration
Public Function fn(x As Double, theta As Double) As Double
fn = Math.Sin(x) / (Math.Sqrt(Math.Sin(theta) - Math.Sin(x))) ' from reference {2} formula (12b)
End Function
' Return the Complete Elliptic integral of the 1st kind
' Abramowitz and Stegun p.591, formula 17.3.11
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticK(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum += Math.Pow(m, i) * Math.Pow(term, 2)
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
' Return the Complete Elliptic integral of the 2nd kind
' Abramowitz and Stegun p.591, formula 17.3.12
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticE(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum -= Math.Pow(m, i) * Math.Pow(term, 2) / above
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
Friend Partial NotInheritable Class Defined
Private Sub New()
End Sub
' Note: most of these values for m and h/L ratio were found with Wolfram Alpha and either specific intercepts (x=0) or local minima/maxima. They should be constant.
Public Const M_SKETCHY As Double = 0.95 ' value of the m parameter where the curvature near the ends of the curve gets wonky
Public Const M_MAX As Double = 0.993 ' maximum useful value of the m parameter, above which this algorithm for the form of the curve breaks down
Public Const M_ZERO_W As Double = 0.826114765984970336 ' value of the m parameter when width = 0
Public Const M_MAXHEIGHT As Double = 0.701327460663101223 ' value of the m parameter at maximum possible height of the bent rod/wire
Public Const M_DOUBLE_W As Double = 0.180254422335013983 ' minimum value of the m parameter when two width values are possible for a given height and length
Public Const DOUBLE_W_HL_RATIO As Double = 0.257342117984635757 ' value of the height/length ratio above which there are two possible width values
Public Const MAX_HL_RATIO As Double = 0.403140189705650243 ' maximum possible value of the height/length ratio
Public Const MAXERR As Double = 0.0000000001 ' error tolerance
Public Const MAXIT As Integer = 100 ' maximum number of iterations
Public Const ROUNDTO As Integer = 10 ' number of decimal places to round off to
Public Const CURVEDIVS As Integer = 50 ' number of sample points for building the curve (or half-curve as it were)
End Class
- A VB.NET scriptable component
-
98
86
- true
- 15a333e8-a6e9-40f9-ae49-542ab7d2e084
- VB Script
- VB
- true
- 0
- ' -----------------------------------------------------------------
' Elastic Bending Script by Will McElwain
' Created February 2014
'
' DESCRIPTION:
' This beast creates the so-called 'elastica curve', the shape a long, thin rod or wire makes when it is bent elastically (i.e. not permanently). In this case, force
' is assumed to only be applied horizontally (which would be in line with the rod at rest) and both ends are assumed to be pinned or hinged meaning they are free
' to rotate (as opposed to clamped, when the end tangent angle is fixed, usually horizontally). An interesting finding is that it doesn't matter what the material or
' cross-sectional area is, as long as they're uniform along the entire length. Everything makes the same shape when bent as long as it doesn't cross the threshold
' from elastic to plastic (permanent) deformation (I don't bother to find that limit here, but can be found if the yield stress for a material is known).
'
' Key to the formulas used in this script are elliptic integrals, specifically K(m), the complete elliptic integral of the first kind, and E(m), the complete elliptic
' integral of the second kind. There was a lot of confusion over the 'm' and 'k' parameters for these functions, as some people use them interchangeably, but they are
' not the same. m = k^2 (thus k = Sqrt(m)). I try to use the 'm' parameter exclusively to avoid this confusion. Note that there is a unique 'm' parameter for every
' configuration/shape of the elastica curve.
'
' This script tries to find that unique 'm' parameter based on the inputs. The algorithm starts with a test version of m, evaluates an expression, say 2*E(m)/K(m)-1,
' then compares the result to what it should be (in this case, a known width/length ratio). Iterate until the correct m is found. Once we have m, we can then calculate
' all of the other unknowns, then find points that lie on that curve, then interpolate those points for the actual curve. You can also use Wolfram|Alpha as I did to
' find the m parameter based on the equations in this script (example here: http://tiny.cc/t4tpbx for when say width=45.2 and length=67.1).
'
' Other notes:
' * This script works with negative values for width, which will creat a self-intersecting curve (as it should). The curvature of the elastica starts to break down around
' m=0.95 (~154°), but this script will continue to work until M_MAX, m=0.993 (~169°). If you wish to ignore self-intersecting curves, set ignoreSelfIntersecting to True
' * When the only known values are length and height, it is actually possible for certain ratios of height to length to have two valid m values (thus 2 possible widths
' and angles). This script will return them both.
' * Only the first two valid parameters (of the required ones) will be used, meaning if all four are connected (length, width or a PtB, height, and angle), this script will
' only use length and width (or a PtB).
' * Depending on the magnitude of your inputs (say if they're really small, like if length < 10), you might have to increase the constant ROUNDTO at the bottom
'
' REFERENCES:
' {1} "The elastic rod" by M.E. Pacheco Q. & E. Pina, http://www.scielo.org.mx/pdf/rmfe/v53n2/v53n2a8.pdf
' {2} "An experiment in nonlinear beam theory" by A. Valiente, http://www.deepdyve.com/lp/doc/I3lwnxdfGz , also here: http://tiny.cc/Valiente_AEiNBT
' {3} "Snap buckling, writhing and Loop formation In twisted rods" by V.G.A. GOSS, http://myweb.lsbu.ac.uk/~gossga/thesisFinal.pdf
' {4} "Theory of Elastic Stability" by Stephen Timoshenko, http://www.scribd.com/doc/50402462/Timoshenko-Theory-of-Elastic-Stability (start on p. 76)
'
' INPUT:
' PtA - First anchor point (required)
' PtB - Second anchor point (optional, though 2 out of the 4--length, width, height, angle--need to be specified)
' [note that PtB can be the same as PtA (meaning width would be zero)]
' [also note that if a different width is additionally specified that's not equal to the distance between PtA and PtB, then the end point will not equal PtB anymore]
' Pln - Plane of the bent rod/wire, which bends up in the +y direction. The line between PtA and PtB (if specified) must be parallel to the x-axis of this plane
'
' ** 2 of the following 4 need to be specified **
' Len - Length of the rod/wire, which needs to be > 0
' Wid - Width between the endpoints of the curve [note: if PtB is specified in addition, and distance between PtA and PtB <> width, the end point will be relocated
' Ht - Height of the bent rod/wire (when negative, curve will bend downward, relative to the input plane, instead)
' Ang - Inner departure angle or tangent angle (in radians) at the ends of the bent rod/wire. Set up so as width approaches length (thus height approaches zero), angle approaches zero
'
' * Following variables only needed for optional calculating of bending force, not for shape of curve.
' E - Young's modulus (modulus of elasticity) in GPa (=N/m^2) (material-specific. for example, 7075 aluminum is roughly 71.7 GPa)
' I - Second moment of area (or area moment of inertia) in m^4 (cross-section-specific. for example, a hollow rod
' would have I = pi * (outer_diameter^4 - inner_diameter^4) / 32
' Note: E*I is also known as flexural rigidity or bending stiffness
'
' OUTPUT:
' out - only for debugging messages
' Pts - the list of points that approximate the shape of the elastica
' Crv - the 3rd-degree curve interpolated from those points (with accurate start & end tangents)
' L - the length of the rod/wire
' W - the distance (width) between the endpoints of the rod/wire
' H - the height of the bent rod/wire
' A - the tangent angle at the (start) end of the rod/wire
' F - the force needed to hold the rod/wire in a specific shape (based on the material properties & cross-section) **be sure your units for 'I' match your units for the
' rest of your inputs (length, width, etc.). Also note that the critical buckling load (force) that makes the rod/wire start to bend can be found at height=0
'
' THANKS TO:
' Mårten Nettelbladt (thegeometryofbending.blogspot.com)
' Daniel Piker (Kangaroo plugin)
' David Rutten (Grasshopper guru)
' Euler & Bernoulli (the O.G.'s)
'
' -----------------------------------------------------------------
Dim ignoreSelfIntersecting As Boolean = False ' set to True if you don't want to output curves where width < 0, which creates a self-intersecting curve
Dim inCt As Integer = 0 ' count the number of required parameters that are receiving data
Dim length As Double
Dim width As System.Object = Nothing ' need to set as Nothing so we can check if it has been assigned a value later
Dim height As Double
Dim angle As Double
Dim m As Double
Dim multiple_m As New List(Of Double)
Dim AtoB As Line
Dim flip_H As Boolean = False ' if height is negative, this flag will be set
Dim flip_A As Boolean = False ' if angle is negative, this flag will be set
If Not IsSet("Pln") Then
Msg("error", "Base plane is not set")
Return
End If
If Not IsSet("PtA") Then
Msg("error", "Point A is not set")
Return
End If
If Math.Round(Pln.DistanceTo(PtA), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point A is not on the base plane")
Return
End If
Dim refPlane As Plane = Pln ' create a reference plane = input plane and set the origin of it to PtA in case PtA isn't the origin already
refPlane.Origin = PtA
If IsSet("PtB") Then
If Math.Round(Pln.DistanceTo(PtB), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point B is not on the base plane")
Return
End If
AtoB = New Line(PtA, PtB)
If AtoB.Length <> 0 And Not AtoB.Direction.IsPerpendicularTo(Pln.YAxis) Then
Msg("error", "The line between PtA and PtB is not perpendicular to the Y-axis of the specified plane")
Return
End If
inCt += 1
If IsSet("Wid") Then Msg("info", "Wid will override the distance between PtA and PtB. If you do not want this to happen, disconnect PtB or Wid.")
width = PtA.DistanceTo(PtB) ' get the width (distance) between PtA and PtB
Dim refPtB As Point3d
refPlane.RemapToPlaneSpace(PtB, refPtB)
If refPtB.X < 0 Then width = -width ' check if PtB is to the left of PtA...if so, width is negative
End If
If IsSet("Len") Then inCt += 1
If IsSet("Wid") Then inCt += 1
If IsSet("Ht") Then inCt += 1
If IsSet("Ang") Then inCt += 1
If inCt > 2 Then Msg("info", "More parameters set than are required (out of length, width, height, angle). Only using the first two valid ones.")
' check for connected/specified inputs. note: only the first two that it comes across will be used
If IsSet("Len") Then ' if length is specified then...
If Len <= 0 Then
Msg("error", "Length cannot be negative or zero")
Return
End If
If IsSet("Wid") Then ' find height & angle based on length and specified width
If Wid > Len Then
Msg("error", "Width is greater than length")
Return
End If
If Wid = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
width = Wid
Else
m = SolveMFromLenWid(Len, Wid)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
width = Wid
End If
Else If width IsNot Nothing Then ' find height & angle based on length and calculated width (distance between PtA and PtB)
If width > Len Then
Msg("error", "Width is greater than length")
Return
End If
If width = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
Else
m = SolveMFromLenWid(Len, width)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
Else If IsSet("Ht") Then ' find width & angle based on length and height ** possible to return 2 results **
If Math.Abs(Ht / Len) > Defined.MAX_HL_RATIO Then
Msg("error", "Height not possible with given length")
Return
End If
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
width = Len
angle = 0
Else
multiple_m = SolveMFromLenHt(Len, Ht) ' note that it's possible for two values of m to be found if height is close to max height
If multiple_m.Count = 1 Then ' if there's only one m value returned, calculate the width & angle here. we'll deal with multiple m values later
m = multiple_m.Item(0)
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
End If
height = Ht
Else If IsSet("Ang") Then ' find width & height based on length and angle
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
width = Len
height = 0
Else
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to length")
Return
End If
length = Len
Else If IsSet("Wid") Then ' if width is specified then...
If IsSet("Ht") Then ' find length & angle based on specified width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = Wid
angle = 0
Else
m = SolveMFromWidHt(Wid, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on specified width and angle
If Wid = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = Wid
height = 0
Else
length = Wid / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to width (Wid)")
Return
End If
width = Wid
Else If width IsNot Nothing Then ' if width is determined by PtA and PtB then...
If IsSet("Ht") Then ' find length & angle based on calculated width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = width
angle = 0
Else
m = SolveMFromWidHt(width, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on calculated width and angle
If width = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = width
height = 0
Else
length = width / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to PtA and PtB")
Return
End If
Else If IsSet("Ht") Then ' if height is specified then...
If IsSet("Ang") Then ' find length & width based on height and angle
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_H = True
flip_A = True
End If
If Ht = 0 Then
Msg("error", "Height can't = 0 if only height and angle are specified")
Return
Else
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = Not flip_A
flip_H = Not flip_H
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then
Msg("error", "Angle can't = 0 if only height and angle are specified")
Return
Else
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
width = Cal_W(length, m) ' L * (2 * E(m) / K(m) - 1)
End If
angle = Ang
End If
height = Ht
Else
Msg("error", "Need to specify one more parameter in addition to height")
Return
End If
Else If IsSet("Ang") Then
Msg("error", "Need to specify one more parameter in addition to angle")
Return
Else
Msg("error", "Need to specify two of the four parameters: length, width (or PtB), height, and angle")
Return
End If
If m > Defined.M_MAX Then
Msg("error", "Form of curve not solvable with current algorithm and given inputs")
Return
End If
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
If multiple_m.Count > 1 Then ' if there is more than one m value returned, calculate the width, angle, and curve for each
Dim multi_pts As New DataTree(Of Point3d)
Dim multi_crv As New List(Of Curve)
Dim tmp_pts As New List(Of Point3d)
Dim multi_W, multi_A, multi_F As New List(Of Double)
Dim j As Integer = 0 ' used for creating a new branch (GH_Path) for storing pts which is itself a list of points
For Each m_val As Double In multiple_m
width = Cal_W(length, m_val) 'length * (2 * EllipticE(m_val) / EllipticK(m_val) - 1)
If width < 0 And ignoreSelfIntersecting Then
Msg("warning", "One curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Continue For
End If
If m_val >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve whose width = " & Math.Round(width, 4) & " is not guaranteed")
angle = Cal_A(m_val) 'Math.Asin(2 * m_val - 1)
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
tmp_pts = FindBendForm(length, width, m_val, angle, refPlane)
multi_pts.AddRange(tmp_pts, New GH_Path(j))
multi_crv.Add(MakeCurve(tmp_pts, angle, refPlane))
multi_W.Add(width)
If flip_A Then angle = -angle
multi_A.Add(angle)
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
multi_F.Add(EllipticK(m_val) ^ 2 * E * I / length ^ 2) ' from reference {4} pg. 79
j += 1
refPlane.Origin = PtA ' reset the reference plane origin to PtA for the next m_val
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m_val & ", k=" & Math.Sqrt(m_val) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
Next
' assign the outputs
Pts = multi_pts
Crv = multi_crv
L = length
W = multi_W
If flip_H Then height = -height
H = height
A = multi_A
F = multi_F
Else ' only deal with the single m value
If m >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve at these parameters is not guaranteed")
If width < 0 And ignoreSelfIntersecting Then
Msg("error", "Curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Return
End If
Pts = FindBendForm(length, width, m, angle, refPlane)
Crv = MakeCurve(pts, angle, refPlane)
L = length
W = width
If flip_H Then height = -height
H = height
If flip_A Then angle = -angle
A = angle
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
F = EllipticK(m) ^ 2 * E * I / length ^ 2 ' from reference {4} pg. 79. Note: the critical buckling (that makes the rod/wire start to bend) can be found at height=0 (width=length)
'height = Math.Sqrt(((2 * Len / 5) ^ 2 - ((Wid - Len / 5) / 2) ^ 2) ' quick approximation discovered by Mårten of 'Geometry of Bending' fame ( http://tiny.cc/it2pbx )
'width = (Len +/- 2 * Math.Sqrt(4 * Len ^ 2 - 25 * Ht ^ 2)) / 5 ' derived from above
'length = (2 * Math.Sqrt(15 * Ht ^ 2 + 4 * Wid ^ 2) - Wid) / 3 ' derived from above
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m & ", k=" & Math.Sqrt(m) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
End If
-
1797
201
84
184
-
1839
293
- 9
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 8
- 3ede854e-c753-40eb-84cb-b48008f14fd4
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- true
- Script Variable PtA
- 512bccc3-6c0e-4ef4-ba24-8685c3ee8d8c
- PtA
- PtA
- true
- 0
- true
- 1813e6b2-8594-4cdf-882c-e312c60bd7f7
- 1
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
1799
203
25
20
-
1813
213
- true
- Script Variable PtB
- d879c694-aa7a-49cc-885b-4d3c9e0e85df
- PtB
- PtB
- true
- 0
- true
- 0
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
1799
223
25
20
-
1813
233
- true
- Script Variable Pln
- 0b814522-7d00-47c6-9c48-1e46bee924f2
- Pln
- Pln
- true
- 0
- true
- f9c309f7-e784-42bd-ac1d-c6f978935e00
- 1
- 3897522d-58e9-4d60-b38c-978ddacfedd8
-
1799
243
25
20
-
1813
253
- true
- Script Variable Len
- 693f977f-077d-410b-a1cc-bc37f0473ad9
- Len
- Len
- true
- 0
- true
- ce3bf1e3-3694-43ca-b804-94bf1ac205b6
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
1799
263
25
20
-
1813
273
- true
- Script Variable Wid
- e718cabe-f163-44e2-bf0e-4866946c6c49
- Wid
- Wid
- true
- 0
- true
- 2dac057e-8756-4d2f-b7af-61904cb5801a
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
1799
283
25
20
-
1813
293
- true
- Script Variable Ht
- f8027746-ba7f-4f8e-bb9c-fa5b544e826b
- Ht
- Ht
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
1799
303
25
20
-
1813
313
- true
- Script Variable Ang
- 50106206-1bb3-43fe-bd4f-366e3b16274a
- Ang
- Ang
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
1799
323
25
20
-
1813
333
- true
- Script Variable E
- 1d6edbeb-7707-43da-8d81-c55c2a788b19
- E
- E
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
1799
343
25
20
-
1813
353
- true
- Script Variable I
- 06ae685a-2839-4dc2-a276-de0409a26bad
- I
- I
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
1799
363
25
20
-
1813
373
- 1
- Print, Reflect and Error streams
- 20755b5a-7694-4c4e-82c2-fb013dc3fe1b
- out
- out
- false
- 0
-
1854
203
25
22
-
1866.5
214.25
- Output parameter Pts
- b6862774-22a9-4557-8df9-4e105338905c
- Pts
- Pts
- false
- 0
-
1854
225
25
23
-
1866.5
236.75
- Output parameter Crv
- 8f545f02-550b-41fb-8dd0-70baaad81a72
- Crv
- Crv
- false
- 0
-
1854
248
25
22
-
1866.5
259.25
- Output parameter L
- d7f4a38f-b681-4226-a169-d484336986a2
- L
- L
- false
- 0
-
1854
270
25
23
-
1866.5
281.75
- Output parameter W
- ce2227d2-88d5-44a1-b925-e842136dca13
- W
- W
- false
- 0
-
1854
293
25
22
-
1866.5
304.25
- Output parameter H
- 1c6a682f-bab0-45c4-b876-7f71802d69ab
- H
- H
- false
- 0
-
1854
315
25
23
-
1866.5
326.75
- Output parameter A
- 24ef080a-aae1-4bd9-a2eb-97cd1569a733
- A
- A
- false
- 0
-
1854
338
25
22
-
1866.5
349.25
- Output parameter F
- 057d392c-b422-4b34-a8df-30546d6c59e2
- F
- F
- false
- 0
-
1854
360
25
23
-
1866.5
371.75
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 2dac057e-8756-4d2f-b7af-61904cb5801a
- Number Slider
- width
- false
- 0
-
1346
281
382
20
-
1346.563
281.9091
- 2
- 1
- 0
- 400
- -130
- 0
- -43.19
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- ce3bf1e3-3694-43ca-b804-94bf1ac205b6
- Number Slider
- length
- false
- 0
-
1344
255
382
20
-
1344.994
255.0591
- 2
- 1
- 0
- 400
- 0
- 0
- 225
- fbac3e32-f100-4292-8692-77240a42fd1a
- Point
- Contains a collection of three-dimensional points
- true
- 8083dba1-6a1d-4290-9c38-1186214db9bc
- Point
- Pt
- false
- b6862774-22a9-4557-8df9-4e105338905c
- 1
-
1969
163
50
24
-
1994.448
175.7781
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 3e685539-f44c-4607-be6b-cd3c05e3c5eb
- Panel
- false
- 0
- 4cd71eb6-cfaa-4a47-a72d-f24e55334beb
- 1
- Double click to edit panel content…
-
2027
378
105
55
- 0
- 0
- 0
-
2027.304
378.139
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 0d77c51e-584f-44e8-aed2-c2ddf4803888
- Degrees
- Convert an angle specified in radians to degrees
- 25514f49-1dae-40e1-8f32-66e3ea2dc7bd
- Degrees
- Deg
-
1939
389
64
28
-
1969
403
- Angle in radians
- 811b950c-3df2-44de-b7c6-6ffa4c6f2250
- Radians
- R
- false
- 24ef080a-aae1-4bd9-a2eb-97cd1569a733
- 1
-
1941
391
13
24
-
1949
403
- Angle in degrees
- 4cd71eb6-cfaa-4a47-a72d-f24e55334beb
- Degrees
- D
- false
- 0
-
1984
391
17
24
-
1992.5
403
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- f3d440d6-99af-4801-8175-5110376379c5
- Construct Point
- Pt
-
1654
139
67
64
-
1685
171
- {x} coordinate
- 30c954ff-f9a8-4e9e-8c9e-f59a9c5d291c
- X coordinate
- X
- false
- 7feb34e6-c435-40ef-a40e-e2792a845fb9
- 1
-
1656
141
14
20
-
1664.5
151
- 1
- 1
- {0}
- 0
- {y} coordinate
- ae4bac11-a219-4f42-a0e6-d6bf63aeb9fa
- Y coordinate
- Y
- false
- 0
-
1656
161
14
20
-
1664.5
171
- 1
- 1
- {0}
- 0
- {z} coordinate
- 24106b26-bc67-44c4-a1e9-15b116c3613c
- Z coordinate
- Z
- false
- 0
-
1656
181
14
20
-
1664.5
191
- 1
- 1
- {0}
- 0
- Point coordinate
- 1813e6b2-8594-4cdf-882c-e312c60bd7f7
- Point
- Pt
- false
- 0
-
1700
141
19
60
-
1709.5
171
- d5967b9f-e8ee-436b-a8ad-29fdcecf32d5
- Curve
- Contains a collection of generic curves
- 3be0014f-c7bb-45c2-a96c-88d0e7dd1d16
- Curve
- Crv
- false
- 8f545f02-550b-41fb-8dd0-70baaad81a72
- 1
-
1969
206
50
24
-
1994.437
218.3081
- 17b7152b-d30d-4d50-b9ef-c9fe25576fc2
- XY Plane
- World XY plane.
- true
- d0010e01-3735-4f83-b1a6-500844575bf9
- XY Plane
- XY
-
1659
214
64
28
-
1690
228
- Origin of plane
- 2c415a43-0493-4511-bc80-751474a0da20
- Origin
- O
- false
- 0
-
1661
216
14
24
-
1669.5
228
- 1
- 1
- {0}
-
0
0
0
- World XY plane
- f9c309f7-e784-42bd-ac1d-c6f978935e00
- Plane
- P
- false
- 0
-
1705
216
16
24
-
1713
228
- a4cd2751-414d-42ec-8916-476ebf62d7fe
- Radians
- Convert an angle specified in degrees to radians
- 8fe257f5-d9cb-49d1-b6c9-0275b7bb1e07
- Radians
- Rad
-
1664
333
64
28
-
1695
347
- Angle in degrees
- 6b4b4cf1-fd46-40c8-9f67-929d72db351b
- Degrees
- D
- false
- 364d3276-a223-4ce8-826c-4071f2924b37
- 1
-
1666
335
14
24
-
1674.5
347
- Angle in radians
- c9958f3c-a438-4f78-a3b0-79c2730cd794
- Radians
- R
- false
- 0
-
1710
335
16
24
-
1718
347
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 364d3276-a223-4ce8-826c-4071f2924b37
- Number Slider
- angle °
- false
- 0
-
1351
340
295
20
-
1351.752
340.978
- 2
- 1
- 0
- 170
- -170
- 0
- -42.08
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 49784903-21d7-4279-9bef-a75b6aa5db52
- Panel
- false
- 0
- d7f4a38f-b681-4226-a169-d484336986a2
- 1
- Double click to edit panel content…
-
1924
257
97
38
- 0
- 0
- 0
-
1924.427
257.7051
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 4aa4b973-077b-4bf3-b682-1bab56120052
- Panel
- false
- 0
- ce2227d2-88d5-44a1-b925-e842136dca13
- 1
- Double click to edit panel content…
-
2035
282
105
55
- 0
- 0
- 0
-
2035.346
282.573
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 372b06f9-a8b8-4e7d-b9a0-47795f8b6db6
- Panel
- false
- 0
- 1c6a682f-bab0-45c4-b876-7f71802d69ab
- 1
- Double click to edit panel content…
-
1923
318
97
38
- 0
- 0
- 0
-
1923.371
318.089
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 7feb34e6-c435-40ef-a40e-e2792a845fb9
- Panel
- false
- 0
- 0
- -75
-
1568
140
50
20
- 0
- 0
- 0
-
1568.331
140.4951
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
2269.006
1162.356
-
2646.125
1163.049
-
2646.09
1181.682
-
2268.972
1180.989
- A quick note
- Microsoft Sans Serif
- 61792023-c3a4-44db-a658-c546e321f080
- false
- Scribble
- Scribble
- 25
- And the real raison d'être: tents!
-
2263.972
1157.356
387.1528
29.32556
-
2269.006
1162.356
- 575660b1-8c79-4b8d-9222-7ab4a6ddb359
- Rectangle 2Pt
- Create a rectangle from a base plane and two points
- b8a48901-2a87-4e7d-870b-46ddd3c0a406
- Rectangle 2Pt
- Rec 2Pt
-
2171
1539
64
84
-
2202
1581
- Rectangle base plane
- e2d6cfd4-201c-479e-a449-d47449b5d99c
- Plane
- P
- false
- 8d8d0823-8c31-466e-89ab-c417764715c3
- 1
-
2173
1541
14
20
-
2181.5
1551
- 1
- 1
- {0}
-
0
0
0
1
0
0
0
1
0
- First corner point.
- c31a60ef-1b6b-45b3-b296-290087f567bf
- Point A
- A
- false
- 9ac73f55-39ae-429e-8dc8-8e7f958b4042
- 1
-
2173
1561
14
20
-
2181.5
1571
- 1
- 1
- {0}
-
0
0
0
- Second corner point.
- 84fdc143-bd3e-4515-a76c-b9793c5c039d
- Point B
- B
- false
- a8fa466b-7cde-4211-998f-da025b67f6b6
- 1
-
2173
1581
14
20
-
2181.5
1591
- 1
- 1
- {0}
-
10
5
0
- Rectangle corner fillet radius
- 789908b6-b304-431d-b593-c2d0b7f80aa3
- Radius
- R
- false
- 0
-
2173
1601
14
20
-
2181.5
1611
- 1
- 1
- {0}
- 0
- Rectangle defined by P, A and B
- 5cf2e6df-da94-4f18-9535-133a50f579e9
- Rectangle
- R
- false
- 0
-
2217
1541
16
40
-
2225
1561
- Length of rectangle curve
- 7e0b11dd-d81c-4da2-b222-5309b51b0636
- Length
- L
- false
- 0
-
2217
1581
16
40
-
2225
1601
- 17b7152b-d30d-4d50-b9ef-c9fe25576fc2
- XY Plane
- World XY plane.
- true
- 03446bc9-f51d-46c6-85eb-615230f3c249
- XY Plane
- XY
-
2099
1495
64
28
-
2130
1509
- Origin of plane
- 8b2fbbc3-5be3-46d2-9834-1a1a5caea969
- Origin
- O
- false
- 0
-
2101
1497
14
24
-
2109.5
1509
- 1
- 1
- {0}
-
0
0
0
- World XY plane
- 8d8d0823-8c31-466e-89ab-c417764715c3
- Plane
- P
- false
- 0
-
2145
1497
16
24
-
2153
1509
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- 7d498686-2e4d-42a6-adc7-13da767447ec
- Construct Point
- Pt
-
1530
1185
67
64
-
1561
1217
- {x} coordinate
- bb3e48a5-a17f-4d87-8d40-67dd01b081eb
- X coordinate
- X
- false
- 0903a6c2-e102-41a9-8326-3f9533f91f9f
- 1
-
1532
1187
14
20
-
1540.5
1197
- 1
- 1
- {0}
- 0
- {y} coordinate
- c46a319c-3740-4362-8bff-3454b1d2a6cc
- Y coordinate
- Y
- false
- 17a61eca-a95a-4f8b-aa55-052523e686bc
- 1
-
1532
1207
14
20
-
1540.5
1217
- 1
- 1
- {0}
- 0
- {z} coordinate
- 6c63b308-c5d5-44f6-a259-04c99b457c22
- Z coordinate
- Z
- false
- 0
-
1532
1227
14
20
-
1540.5
1237
- 1
- 1
- {0}
- 0
- Point coordinate
- f70a66ec-d9db-496d-9885-4b577f135593
- Point
- Pt
- false
- 0
-
1576
1187
19
60
-
1585.5
1217
- a0d62394-a118-422d-abb3-6af115c75b25
- Addition
- Mathematical addition
- true
- f35af83d-b4d8-44ef-9f78-7dc1ed1ad4dd
- Addition
- A+B
-
1688
1286
64
44
-
1719
1308
- 2
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 1
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- First item for addition
- f3b877be-ea2c-4706-b8e6-cf34d2796bca
- A
- A
- true
- f70a66ec-d9db-496d-9885-4b577f135593
- 1
-
1690
1288
14
20
-
1698.5
1298
- Second item for addition
- 16e574ce-9435-47c5-850d-a8fc5152e81d
- B
- B
- true
- 60a1321b-0d85-4215-ac31-f94c7015ccf2
- 1
-
1690
1308
14
20
-
1698.5
1318
- Result of addition
- 9ac73f55-39ae-429e-8dc8-8e7f958b4042
- Result
- R
- false
- 0
-
1734
1288
16
40
-
1742
1308
- 56b92eab-d121-43f7-94d3-6cd8f0ddead8
- Vector XYZ
- Create a vector from {xyz} components.
- true
- 25bf0db5-4adb-4408-bfee-7d3611f1d1b6
- Vector XYZ
- Vec
-
1576
1323
64
64
-
1607
1355
- Vector {x} component
- ec060dc1-0d2b-4706-ac14-728c097f877f
- X component
- X
- false
- 9b5d1997-6eb6-419e-84a2-da5dc70f5477
- 1
-
1578
1325
14
20
-
1586.5
1335
- 1
- 1
- {0}
- 0
- Vector {y} component
- 1554f826-50eb-4842-ad0c-e1591646e701
- Y component
- Y
- false
- b582b4c2-046d-4816-9bf2-b7e40b12e3a1
- 1
-
1578
1345
14
20
-
1586.5
1355
- 1
- 1
- {0}
- 0
- Vector {z} component
- c5b4970d-6668-445e-b8a3-7d736d0f83dc
- Z component
- Z
- false
- 0
-
1578
1365
14
20
-
1586.5
1375
- 1
- 1
- {0}
- 0
- Vector construct
- 60a1321b-0d85-4215-ac31-f94c7015ccf2
- Vector
- V
- false
- 0
-
1622
1325
16
30
-
1630
1340
- Vector length
- 614a3c6d-0b33-40ad-81d3-d0dfd2cda65f
- Length
- L
- false
- 0
-
1622
1355
16
30
-
1630
1370
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 9b5d1997-6eb6-419e-84a2-da5dc70f5477
- Panel
- false
- 0
- 0
- 3
-
1491
1321
50
20
- 0
- 0
- 0
-
1491.106
1321.658
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- b582b4c2-046d-4816-9bf2-b7e40b12e3a1
- Panel
- false
- 0
- 0
- 2
-
1489
1351
50
20
- 0
- 0
- 0
-
1489.186
1351.098
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 9abae6b7-fa1d-448c-9209-4a8155345841
- Deconstruct
- Deconstruct a point into its component parts.
- true
- 04d13d9d-5383-4696-b406-0fc16bb9a913
- Deconstruct
- pDecon
-
1704
1432
64
64
-
1734
1464
- Input point
- ac0ad7b1-bf77-4354-ae03-3ed56f7694ac
- Point
- P
- false
- 9ac73f55-39ae-429e-8dc8-8e7f958b4042
- 1
-
1706
1434
13
60
-
1714
1464
- Point {x} component
- 986c6ad6-35ae-433f-bd24-072861a5425d
- X component
- X
- false
- 0
-
1749
1434
17
20
-
1757.5
1444
- Point {y} component
- 2c914091-22c1-40d8-abc1-4ccddd24e6ea
- Y component
- Y
- false
- 0
-
1749
1454
17
20
-
1757.5
1464
- Point {z} component
- eb73bdaa-9667-4377-9a20-f2e4e4e9cdbf
- Z component
- Z
- false
- 0
-
1749
1474
17
20
-
1757.5
1484
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 91f17ed9-335a-446e-9d6c-b9c687cba0f0
- Number Slider
- Length
- false
- 0
-
1456
1597
263
20
-
1456.337
1597.275
- 1
- 1
- 0
- 100
- 0
- 0
- 88
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 0fd09915-ec8a-4a40-989a-123b9e68d06c
- Number Slider
- Width
- false
- 0
-
1457
1655
264
20
-
1457.087
1655.275
- 1
- 1
- 0
- 100
- 0
- 0
- 54
- a0d62394-a118-422d-abb3-6af115c75b25
- Addition
- Mathematical addition
- true
- 425cffae-604f-493a-a5c9-d68e3739d648
- Addition
- A+B
-
1786
1573
64
44
-
1817
1595
- 2
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 1
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- First item for addition
- bd91b324-b139-4235-80e4-f5e0f3620809
- A
- A
- true
- 986c6ad6-35ae-433f-bd24-072861a5425d
- 1
-
1788
1575
14
20
-
1796.5
1585
- Second item for addition
- a87172e3-431e-4ddf-a937-60b5bc804451
- B
- B
- true
- 91f17ed9-335a-446e-9d6c-b9c687cba0f0
- 1
-
1788
1595
14
20
-
1796.5
1605
- Result of addition
- ef5b5c46-d28c-4d3d-8719-82ebb12862d2
- Result
- R
- false
- 0
-
1832
1575
16
40
-
1840
1595
- a0d62394-a118-422d-abb3-6af115c75b25
- Addition
- Mathematical addition
- true
- c608fbec-5b75-4c4d-b4d8-48a376f3cd5c
- Addition
- A+B
-
1790
1635
64
44
-
1821
1657
- 2
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 1
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- First item for addition
- bd152880-8e47-4e39-af2c-724b79caa7ea
- A
- A
- true
- 2c914091-22c1-40d8-abc1-4ccddd24e6ea
- 1
-
1792
1637
14
20
-
1800.5
1647
- Second item for addition
- 2ff8f792-cc71-4183-9cdf-57524cacfb82
- B
- B
- true
- 0fd09915-ec8a-4a40-989a-123b9e68d06c
- 1
-
1792
1657
14
20
-
1800.5
1667
- Result of addition
- 49b19326-ddaa-450c-a91b-d85295831ca1
- Result
- R
- false
- 0
-
1836
1637
16
40
-
1844
1657
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- true
- 0025b0b3-cd63-4b6e-a883-c991f59c2549
- Construct Point
- Pt
-
1994
1573
67
64
-
2025
1605
- {x} coordinate
- e0588cd2-61aa-4863-98e0-1e9a7f21a1be
- X coordinate
- X
- false
- ef5b5c46-d28c-4d3d-8719-82ebb12862d2
- 1
-
1996
1575
14
20
-
2004.5
1585
- 1
- 1
- {0}
- 0
- {y} coordinate
- 037a8251-883a-40af-a11c-21b9ae0ecb92
- Y coordinate
- Y
- false
- 49b19326-ddaa-450c-a91b-d85295831ca1
- 1
-
1996
1595
14
20
-
2004.5
1605
- 1
- 1
- {0}
- 0
- {z} coordinate
- 54de041d-38b7-41dc-8680-c6bfa86d9ba3
- Z coordinate
- Z
- false
- 0
-
1996
1615
14
20
-
2004.5
1625
- 1
- 1
- {0}
- 0
- Point coordinate
- a8fa466b-7cde-4211-998f-da025b67f6b6
- Point
- Pt
- false
- 0
-
2040
1575
19
60
-
2049.5
1605
- a0d62394-a118-422d-abb3-6af115c75b25
- Addition
- Mathematical addition
- true
- 66ed28c2-e779-444a-9c0b-9bd8f26ea017
- Addition
- A+B
-
2124
1296
64
44
-
2155
1318
- 2
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 1
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- First item for addition
- e86f9ce0-a5ad-4770-854f-f91bc82511aa
- A
- A
- true
- a8fa466b-7cde-4211-998f-da025b67f6b6
- 1
-
2126
1298
14
20
-
2134.5
1308
- Second item for addition
- 372d26ca-bd41-418e-9a3f-36c4cb124978
- B
- B
- true
- 60a1321b-0d85-4215-ac31-f94c7015ccf2
- 1
-
2126
1318
14
20
-
2134.5
1328
- Result of addition
- 79d26b1a-d554-4adf-802a-54c1a82df2de
- Result
- R
- false
- 0
-
2170
1298
16
40
-
2178
1318
- f12daa2f-4fd5-48c1-8ac3-5dea476912ca
- Mirror
- Mirror an object.
- true
- 5caa758f-68a9-4e10-8541-d9dcff111255
- Mirror
- Mirror
-
2176
1350
65
44
-
2207
1372
- Base geometry
- c1d5c25c-8138-49ab-bd00-a02680a1f99d
- Geometry
- G
- true
- 60a1321b-0d85-4215-ac31-f94c7015ccf2
- 1
-
2178
1352
14
20
-
2186.5
1362
- Mirror plane
- e3d075b2-072b-47d9-9463-c3aa654ad224
- Plane
- P
- false
- 48d4eb53-6ad2-481f-8610-55d9944a22c3
- 1
-
2178
1372
14
20
-
2186.5
1382
- 1
- 1
- {0}
-
0
0
0
0
1
0
0
0
1
- Mirrored geometry
- bf8b3e5d-d755-43fb-8734-c94ed4d00bba
- Geometry
- G
- false
- 0
-
2222
1352
17
20
-
2230.5
1362
- Transformation data
- 4ee0f674-5c0f-410f-b9f6-08a3604b4334
- Transform
- X
- false
- 0
-
2222
1372
17
20
-
2230.5
1382
- fad344bc-09b1-4855-a2e6-437ef5715fe3
- YZ Plane
- World YZ plane.
- true
- 272c02f3-8054-4da2-b750-4109a8b8c37e
- YZ Plane
- YZ
-
2091
1367
64
28
-
2122
1381
- Origin of plane
- 37e34f49-3112-4952-89a1-4b43e1db22f2
- Origin
- O
- false
- 0
-
2093
1369
14
24
-
2101.5
1381
- 1
- 1
- {0}
-
0
0
0
- World YZ plane
- 48d4eb53-6ad2-481f-8610-55d9944a22c3
- Plane
- P
- false
- 0
-
2137
1369
16
24
-
2145
1381
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- true
- 158a8811-4a85-4636-9d80-bb6a389c6dc5
- Construct Point
- Pt
-
1987
1388
67
64
-
2018
1420
- {x} coordinate
- 9c32aac2-60cd-43ce-8916-e951db46c16d
- X coordinate
- X
- false
- 986c6ad6-35ae-433f-bd24-072861a5425d
- 1
-
1989
1390
14
20
-
1997.5
1400
- 1
- 1
- {0}
- 0
- {y} coordinate
- a95132f4-4546-4352-9af9-19e27eedb3c9
- Y coordinate
- Y
- false
- 49b19326-ddaa-450c-a91b-d85295831ca1
- 1
-
1989
1410
14
20
-
1997.5
1420
- 1
- 1
- {0}
- 0
- {z} coordinate
- 8802bfb6-39ba-40ec-84a0-199a2ccc0b6a
- Z coordinate
- Z
- false
- 0
-
1989
1430
14
20
-
1997.5
1440
- 1
- 1
- {0}
- 0
- Point coordinate
- 21b1fb4d-d8f9-4dca-a50f-bda44d8d40b3
- Point
- Pt
- false
- 0
-
2033
1390
19
60
-
2042.5
1420
- a0d62394-a118-422d-abb3-6af115c75b25
- Addition
- Mathematical addition
- true
- e0d2b78b-5b2e-48e8-af51-67f77e6fe2e3
- Addition
- A+B
-
2364
1520
64
44
-
2395
1542
- 2
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 1
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- First item for addition
- 06d9a75f-442d-48a1-ace0-8e88067ed67f
- A
- A
- true
- 21b1fb4d-d8f9-4dca-a50f-bda44d8d40b3
- 1
-
2366
1522
14
20
-
2374.5
1532
- Second item for addition
- 6e986d97-59c1-46d7-8208-3fa2d487fe5c
- B
- B
- true
- bf8b3e5d-d755-43fb-8734-c94ed4d00bba
- 1
-
2366
1542
14
20
-
2374.5
1552
- Result of addition
- 5b37f206-7db4-44b0-ba0f-6175cec13953
- Result
- R
- false
- 0
-
2410
1522
16
40
-
2418
1542
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- true
- 8ecbb3d6-8916-43ff-9ea1-e19a4fb39844
- Construct Point
- Pt
-
1996
1662
67
64
-
2027
1694
- {x} coordinate
- 8e8e1801-b640-4212-9871-fb70a85ac93c
- X coordinate
- X
- false
- ef5b5c46-d28c-4d3d-8719-82ebb12862d2
- 1
-
1998
1664
14
20
-
2006.5
1674
- 1
- 1
- {0}
- 0
- {y} coordinate
- 26f967a7-45e3-4567-8d5b-e583254c129a
- Y coordinate
- Y
- false
- 2c914091-22c1-40d8-abc1-4ccddd24e6ea
- 1
-
1998
1684
14
20
-
2006.5
1694
- 1
- 1
- {0}
- 0
- {z} coordinate
- dfcf11d4-ae95-4bcd-afb7-606d1755dc76
- Z coordinate
- Z
- false
- 0
-
1998
1704
14
20
-
2006.5
1714
- 1
- 1
- {0}
- 0
- Point coordinate
- e825beda-2c01-4b73-b180-297fcfe8bbc3
- Point
- Pt
- false
- 0
-
2042
1664
19
60
-
2051.5
1694
- 2c56ab33-c7cc-4129-886c-d5856b714010
- Subtraction
- Mathematical subtraction
- true
- 716d8d38-b0b8-409b-9809-4626eaa49feb
- Subtraction
- A-B
-
2368
1584
64
44
-
2399
1606
- Item to subtract from (minuend)
- 1104ec21-7fa5-4dae-af48-1016aa881210
- A
- A
- false
- e825beda-2c01-4b73-b180-297fcfe8bbc3
- 1
-
2370
1586
14
20
-
2378.5
1596
- Item to subtract (subtrahend)
- a3acb875-c63e-4a60-8e24-40c0d03aba55
- B
- B
- false
- bf8b3e5d-d755-43fb-8734-c94ed4d00bba
- 1
-
2370
1606
14
20
-
2378.5
1616
- The result of the Subtraction
- 40a43f7c-5b18-42a9-934b-a3fca8b86584
- Result
- R
- false
- 0
-
2414
1586
16
40
-
2422
1606
- fbac3e32-f100-4292-8692-77240a42fd1a
- Point
- Contains a collection of three-dimensional points
- true
- 5c0c8191-e5d5-44d8-9b74-ad7b50095c12
- Point
- Pt
- false
- 40a43f7c-5b18-42a9-934b-a3fca8b86584
- 1
-
2466
1587
50
24
-
2491.524
1599.556
- fbac3e32-f100-4292-8692-77240a42fd1a
- Point
- Contains a collection of three-dimensional points
- true
- 83dc0e24-1c12-445e-8647-dffc452baa6a
- Point
- Pt
- false
- 5b37f206-7db4-44b0-ba0f-6175cec13953
- 1
-
2464
1538
50
24
-
2489.024
1550.806
- fbac3e32-f100-4292-8692-77240a42fd1a
- Point
- Contains a collection of three-dimensional points
- true
- c54e879a-bb6c-47c6-b366-aaa5a16a426a
- Point
- Pt
- false
- f70a66ec-d9db-496d-9885-4b577f135593
- 1
-
2387
1270
50
24
-
2412.399
1282.068
- fbac3e32-f100-4292-8692-77240a42fd1a
- Point
- Contains a collection of three-dimensional points
- true
- 72b7092f-b51c-4a8b-b457-5cc6f58de91d
- Point
- Pt
- false
- 79d26b1a-d554-4adf-802a-54c1a82df2de
- 1
-
2387
1315
50
24
-
2412.599
1327.418
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 8526fdb2-be35-4339-84b0-0de9c353ed2c
- Panel
- false
- 0
- 0
- 3
-
2586
1726
50
20
- 0
- 0
- 0
-
2586.39
1726.995
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- a0d62394-a118-422d-abb3-6af115c75b25
- Addition
- Mathematical addition
- e9472173-0e76-45e7-b4b3-2d927d4baecc
- Addition
- A+B
-
2663
1691
64
44
-
2694
1713
- 2
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 1
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- First item for addition
- da0b56ad-280a-4f2a-8298-030632f1527e
- A
- A
- true
- 14cc88f5-707d-4e86-a518-ccdcce6ded66
- 1
-
2665
1693
14
20
-
2673.5
1703
- Second item for addition
- 7467100d-05d3-4ae7-a577-8da37d4b9e55
- B
- B
- true
- 8526fdb2-be35-4339-84b0-0de9c353ed2c
- 1
-
2665
1713
14
20
-
2673.5
1723
- Result of addition
- cd2f5af0-b741-48d5-8bbd-e9695d5278d8
- Result
- R
- false
- 0
-
2709
1693
16
40
-
2717
1713
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 14cc88f5-707d-4e86-a518-ccdcce6ded66
- Number Slider
- Peak Height
- false
- 0
-
2372
1693
263
20
-
2372.275
1693.369
- 1
- 1
- 0
- 72
- 0
- 0
- 44
- 9103c240-a6a9-4223-9b42-dbd19bf38e2b
- Unit Z
- Unit vector parallel to the world {z} axis.
- c51aaec6-9bc7-40d7-ab2d-705fd2e20e1e
- Unit Z
- Z
-
2553
1260
62
28
-
2582
1274
- Unit multiplication
- 2414a112-d958-411b-b27f-8cdf9d0d2480
- Factor
- F
- false
- 0
-
2555
1262
12
24
-
2562.5
1274
- 1
- 1
- {0}
- 1
- World {z} vector
- fdc6f14b-d2af-4143-9fa5-98d72e1496f4
- Unit vector
- V
- false
- 0
-
2597
1262
16
24
-
2605
1274
- 934ede4a-924a-4973-bb05-0dc4b36fae75
- Vector 2Pt
- Create a vector between two points.
- 361f13b0-f722-496a-b487-cfffdce2f9cb
- Vector 2Pt
- Vec2Pt
-
2548
1387
64
64
-
2579
1419
- Base point
- 5e0ee3e7-7ca6-486b-a276-9290daec2c1d
- Point A
- A
- false
- c54e879a-bb6c-47c6-b366-aaa5a16a426a
- 83dc0e24-1c12-445e-8647-dffc452baa6a
- 2
-
2550
1389
14
20
-
2558.5
1399
- Tip point
- 69e066b8-5497-4517-9782-d03091f32b49
- Point B
- B
- false
- 72b7092f-b51c-4a8b-b457-5cc6f58de91d
- 5c0c8191-e5d5-44d8-9b74-ad7b50095c12
- 2
-
2550
1409
14
20
-
2558.5
1419
- Unitize output
- e01e96a4-176c-42b4-baed-01d2da98668f
- Unitize
- U
- false
- 0
-
2550
1429
14
20
-
2558.5
1439
- 1
- 1
- {0}
- false
- Vector
- a09f5810-c5e6-41cf-a732-76ade1d918e1
- Vector
- V
- false
- 0
-
2594
1389
16
30
-
2602
1404
- Vector length
- 15154730-ac41-4df7-abd3-5125f66ed008
- Length
- L
- false
- 0
-
2594
1419
16
30
-
2602
1434
- bc3e379e-7206-4e7b-b63a-ff61f4b38a3e
- Construct Plane
- Construct a plane from an origin point and {x}, {y} axes.
- true
- 1b6a1009-88b9-418a-8918-f95aabbb1c52
- Construct Plane
- Pl
-
2674
1295
66
64
-
2705
1327
- Origin of plane
- 7a695424-f044-41a8-9bf1-a2cbf28cc226
- Origin
- O
- false
- c54e879a-bb6c-47c6-b366-aaa5a16a426a
- 83dc0e24-1c12-445e-8647-dffc452baa6a
- 2
-
2676
1297
14
20
-
2684.5
1307
- 1
- 1
- {0}
-
0
0
0
- X-Axis direction of plane
- c61582e5-1354-459b-babb-382f6952792a
- X-Axis
- X
- false
- a09f5810-c5e6-41cf-a732-76ade1d918e1
- 1
-
2676
1317
14
20
-
2684.5
1327
- 1
- 1
- {0}
-
1
0
0
- Y-Axis direction of plane
- ec988c3e-fd2b-4d2b-aa6a-5e3a9c15a503
- Y-Axis
- Y
- false
- fdc6f14b-d2af-4143-9fa5-98d72e1496f4
- 1
-
2676
1337
14
20
-
2684.5
1347
- 1
- 1
- {0}
-
0
1
0
- Constructed plane
- f5ef3118-8c76-4765-bdd9-16087c3ebb2d
- Plane
- Pl
- false
- 0
-
2720
1297
18
60
-
2729
1327
- 079bd9bd-54a0-41d4-98af-db999015f63d
- VB Script
- Private Function IsSet(ByVal param As String) As Boolean ' Check if an input parameter has data
Dim i As Integer = Component.Params.IndexOfInputParam(param)
If i > -1 Then
Return Component.Params.Input.ElementAt(i).DataType > 1 ' input parameter DataType of 1 means it's not receiving input (internal or external)
Else
Msg("error", "Input parameter '" & param & "' not found")
Return False
End If
End Function
Private Sub Msg(ByVal type As String, ByVal msg As String) ' Output an error, warning, or informational message
Select Case type
Case "error"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, msg)
Print("Error: " & msg)
Case "warning"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, msg)
Print("Warning: " & msg)
Case "info"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, msg)
Print(msg)
End Select
End Sub
' Solve for the m parameter from length and width (reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m))
Private Function SolveMFromLenWid(ByVal L As Double, ByVal w As Double) As Double
If w = 0 Then
Return Defined.M_ZERO_W ' for the boundry condition width = 0, bypass the function and return the known m value
End If
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwl As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwl = 2 * EllipticE(m) / EllipticK(m) - 1 ' calculate w/L with the test value of m
If cwl < w / L Then ' compares the calculated w/L with the actual w/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Solve for the m parameter from length and height (reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m))
' Note that it's actually possible to find 2 valid values for m (hence 2 width values) at certain height values
Private Function SolveMFromLenHt(ByVal L As Double, ByVal h As Double) As List(Of Double)
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim twoWidths As Boolean = h / L >= Defined.DOUBLE_W_HL_RATIO And h / L < Defined.MAX_HL_RATIO ' check to see if h/L is within the range where 2 solutions for the width are possible
Dim m As Double
Dim mult_m As New List(Of Double)
Dim chl As Double
If twoWidths Then
' find the first of two possible solutions for m with the following limits:
lower = Defined.M_DOUBLE_W ' see constants at bottom of script
upper = Defined.M_MAXHEIGHT ' see constants at bottom of script
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
' then find the second of two possible solutions for m with the following limits:
lower = Defined.M_MAXHEIGHT ' see constants at bottom of script
upper = 1
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl < h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
If m <= Defined.M_MAX Then ' return this m parameter only if it falls within the maximum useful value (above which the curve breaks down)
mult_m.Add(m)
End If
Else
' find the one possible solution for the m parameter
upper = Defined.M_DOUBLE_W ' limit the upper end of the search to the maximum value of m for which only one solution exists
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
End If
Return mult_m
End Function
' Solve for the m parameter from width and height (derived from reference {1} equations (33) and (34) with same notes as above)
Private Function SolveMFromWidHt(ByVal w As Double, ByVal h As Double) As Double
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwh As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwh = (2 * EllipticE(m) - EllipticK(m)) / Math.Sqrt(m) ' calculate w/h with the test value of m
If cwh < w / h Then ' compares the calculated w/h with the actual w/h then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Calculate length based on height and an m parameter, derived from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_L(ByVal h As Double, ByVal m As Double) As Double
Return h * EllipticK(m) / Math.Sqrt(m)
End Function
' Calculate width based on length and an m parameter, derived from reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m)
Private Function Cal_W(ByVal L As Double, ByVal m As Double) As Double
Return L * (2 * EllipticE(m) / EllipticK(m) - 1)
End Function
' Calculate height based on length and an m parameter, from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_H(ByVal L As Double, ByVal m As Double) As Double
Return L * Math.Sqrt(m) / EllipticK(m)
End Function
' Calculate the unique m parameter based on a start tangent angle, from reference {2}, just above equation (9a), that states k = Sin(angle / 2 + Pi / 4),
' but as m = k^2 and due to this script's need for an angle rotated 90° versus the one in reference {1}, the following formula is the result
' New note: verified by reference {4}, pg. 78 at the bottom
Private Function Cal_M(ByVal a As Double) As Double
Return (1 - Math.Cos(a)) / 2 ' equal to Sin^2(a/2) too
End Function
' Calculate start tangent angle based on an m parameter, derived from above formula
Private Function Cal_A(ByVal m As Double) As Double
Return Math.Acos(1 - 2 * m)
End Function
' This is the heart of this script, taking the found (or specified) length, width, and angle values along with the found m parameter to create
' a list of points that approximate the shape or form of the elastica. It works by finding the x and y coordinates (which are reversed versus
' the original equations (12a) and (12b) from reference {2} due to the 90° difference in orientation) based on the tangent angle along the curve.
' See reference {2} for more details on how they derived it. Note that to simplify things, the algorithm only calculates the points for half of the
' curve, then mirrors those points along the y-axis.
Private Function FindBendForm(ByVal L As Double, ByVal w As Double, ByVal m As Double, ByVal ang As Double, ByVal refPln As Plane) As List(Of Point3d)
L = L / 2 ' because the below algorithm is based on the formulas in reference {2} for only half of the curve
w = w / 2 ' same
If ang = 0 Then ' if angle (and height) = 0, then simply return the start and end points of the straight line
Dim out As New List(Of Point3d)
out.Add(refPln.PointAt(w, 0, 0))
out.Add(refPln.PointAt(-w, 0, 0))
Return out
End If
Dim x As Double
Dim y As Double
Dim halfCurvePts As New List(Of Point3d)
Dim fullCurvePts As New List(Of Point3d)
Dim translatedPts As New List(Of Point3d)
ang -= Math.PI / 2 ' a hack to allow this algorithm to work, since the original curve in paper {2} was rotated 90°
Dim angB As Double = ang + (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' angB is the 'lowercase theta' which should be in formula {2}(12b) as the interval
' start [a typo...see equation(3)]. It's necessary to start angB at ang + [interval] instead of just ang due to integration failing at angB = ang
halfCurvePts.Add(New Point3d(w, 0, 0)) ' start with this known initial point, as integration will fail when angB = ang
' each point {x, y} is calculated from the tangent angle, angB, that occurs at each point (which is why this iterates from ~ang to -pi/2, the known end condition)
Do While Math.Round(angB, Defined.ROUNDTO) >= Math.Round(-Math.PI / 2, Defined.ROUNDTO)
y = (Math.Sqrt(2) * Math.Sqrt(Math.Sin(ang) - Math.Sin(angB)) * (w + L)) / (2 * EllipticE(m)) ' note that x and y are swapped vs. (12a) and (12b)
x = (L / (Math.Sqrt(2) * EllipticK(m))) * Simpson(angB, -Math.PI / 2, 500, ang) ' calculate the Simpson approximation of the integral (function f below)
' over the interval angB ('lowercase theta') to -pi/2. side note: is 500 too few iterations for the Simson algorithm?
If Math.Round(x, Defined.ROUNDTO) = 0 Then x = 0
halfCurvePts.Add(New Point3d(x, y, 0))
angB += (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' onto the next tangent angle
Loop
' After finding the x and y values for half of the curve, add the {-x, y} values for the rest of the curve
For Each point As Point3d In halfCurvePts
If Math.Round(point.X, Defined.ROUNDTO) = 0 Then
If Math.Round(point.Y, Defined.ROUNDTO) = 0 Then
fullCurvePts.Add(New Point3d(0, 0, 0)) ' special case when width = 0: when x = 0, only duplicate the point when y = 0 too
End If
Else
fullCurvePts.Add(New Point3d(-point.X, point.Y, 0))
End If
Next
halfCurvePts.Reverse
fullCurvePts.AddRange(halfCurvePts)
For Each p As Point3d In fullCurvePts
translatedPts.Add(refPln.PointAt(p.X, p.Y, p.Z)) ' translate the points from the reference plane to the world plane
Next
Return translatedPts
End Function
' Interpolates the points from FindBendForm to create the Elastica curve. Uses start & end tangents for greater accuracy.
Private Function MakeCurve(ByVal pts As List(Of Point3d), ByVal ang As Double, ByVal refPln As Plane) As Curve
If ang <> 0 Then
Dim ts, te As New Vector3d(refPln.XAxis)
ts.Rotate(ang, refPln.ZAxis)
te.Rotate(-ang, refPln.ZAxis)
Return Curve.CreateInterpolatedCurve(pts, 3, CurveKnotStyle.Chord, ts, te) ' 3rd degree curve with 'Chord' Knot Style
Else
Return Curve.CreateInterpolatedCurve(pts, 3) ' if angle (and height) = 0, then simply interpolate the straight line (no start/end tangents)
End If
End Function
' Implements the Simpson approximation for an integral of function f below
Public Function Simpson(a As Double, b As Double, n As Integer, theta As Double) As Double 'n should be an even number
Dim j As Integer, s1 As Double, s2 As Double, h As Double
h = (b - a) / n
s1 = 0
s2 = 0
For j = 1 To n - 1 Step 2
s1 = s1 + fn(a + j * h, theta)
Next j
For j = 2 To n - 2 Step 2
s2 = s2 + fn(a + j * h, theta)
Next j
Simpson = h / 3 * (fn(a, theta) + 4 * s1 + 2 * s2 + fn(b, theta))
End Function
' Specific calculation for the above integration
Public Function fn(x As Double, theta As Double) As Double
fn = Math.Sin(x) / (Math.Sqrt(Math.Sin(theta) - Math.Sin(x))) ' from reference {2} formula (12b)
End Function
' Return the Complete Elliptic integral of the 1st kind
' Abramowitz and Stegun p.591, formula 17.3.11
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticK(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum += Math.Pow(m, i) * Math.Pow(term, 2)
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
' Return the Complete Elliptic integral of the 2nd kind
' Abramowitz and Stegun p.591, formula 17.3.12
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticE(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum -= Math.Pow(m, i) * Math.Pow(term, 2) / above
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
Friend Partial NotInheritable Class Defined
Private Sub New()
End Sub
' Note: most of these values for m and h/L ratio were found with Wolfram Alpha and either specific intercepts (x=0) or local minima/maxima. They should be constant.
Public Const M_SKETCHY As Double = 0.95 ' value of the m parameter where the curvature near the ends of the curve gets wonky
Public Const M_MAX As Double = 0.993 ' maximum useful value of the m parameter, above which this algorithm for the form of the curve breaks down
Public Const M_ZERO_W As Double = 0.826114765984970336 ' value of the m parameter when width = 0
Public Const M_MAXHEIGHT As Double = 0.701327460663101223 ' value of the m parameter at maximum possible height of the bent rod/wire
Public Const M_DOUBLE_W As Double = 0.180254422335013983 ' minimum value of the m parameter when two width values are possible for a given height and length
Public Const DOUBLE_W_HL_RATIO As Double = 0.257342117984635757 ' value of the height/length ratio above which there are two possible width values
Public Const MAX_HL_RATIO As Double = 0.403140189705650243 ' maximum possible value of the height/length ratio
Public Const MAXERR As Double = 0.0000000001 ' error tolerance
Public Const MAXIT As Integer = 100 ' maximum number of iterations
Public Const ROUNDTO As Integer = 10 ' number of decimal places to round off to
Public Const CURVEDIVS As Integer = 50 ' number of sample points for building the curve (or half-curve as it were)
End Class
- A VB.NET scriptable component
-
98
86
- true
- efeac80e-aaa9-43ef-acff-f0dc08a37ca1
- VB Script
- VB
- true
- 0
- ' -----------------------------------------------------------------
' Elastic Bending Script by Will McElwain
' Created February 2014
'
' DESCRIPTION:
' This beast creates the so-called 'elastica curve', the shape a long, thin rod or wire makes when it is bent elastically (i.e. not permanently). In this case, force
' is assumed to only be applied horizontally (which would be in line with the rod at rest) and both ends are assumed to be pinned or hinged meaning they are free
' to rotate (as opposed to clamped, when the end tangent angle is fixed, usually horizontally). An interesting finding is that it doesn't matter what the material or
' cross-sectional area is, as long as they're uniform along the entire length. Everything makes the same shape when bent as long as it doesn't cross the threshold
' from elastic to plastic (permanent) deformation (I don't bother to find that limit here, but can be found if the yield stress for a material is known).
'
' Key to the formulas used in this script are elliptic integrals, specifically K(m), the complete elliptic integral of the first kind, and E(m), the complete elliptic
' integral of the second kind. There was a lot of confusion over the 'm' and 'k' parameters for these functions, as some people use them interchangeably, but they are
' not the same. m = k^2 (thus k = Sqrt(m)). I try to use the 'm' parameter exclusively to avoid this confusion. Note that there is a unique 'm' parameter for every
' configuration/shape of the elastica curve.
'
' This script tries to find that unique 'm' parameter based on the inputs. The algorithm starts with a test version of m, evaluates an expression, say 2*E(m)/K(m)-1,
' then compares the result to what it should be (in this case, a known width/length ratio). Iterate until the correct m is found. Once we have m, we can then calculate
' all of the other unknowns, then find points that lie on that curve, then interpolate those points for the actual curve. You can also use Wolfram|Alpha as I did to
' find the m parameter based on the equations in this script (example here: http://tiny.cc/t4tpbx for when say width=45.2 and length=67.1).
'
' Other notes:
' * This script works with negative values for width, which will creat a self-intersecting curve (as it should). The curvature of the elastica starts to break down around
' m=0.95 (~154°), but this script will continue to work until M_MAX, m=0.993 (~169°). If you wish to ignore self-intersecting curves, set ignoreSelfIntersecting to True
' * When the only known values are length and height, it is actually possible for certain ratios of height to length to have two valid m values (thus 2 possible widths
' and angles). This script will return them both.
' * Only the first two valid parameters (of the required ones) will be used, meaning if all four are connected (length, width or a PtB, height, and angle), this script will
' only use length and width (or a PtB).
' * Depending on the magnitude of your inputs (say if they're really small, like if length < 10), you might have to increase the constant ROUNDTO at the bottom
'
' REFERENCES:
' {1} "The elastic rod" by M.E. Pacheco Q. & E. Pina, http://www.scielo.org.mx/pdf/rmfe/v53n2/v53n2a8.pdf
' {2} "An experiment in nonlinear beam theory" by A. Valiente, http://www.deepdyve.com/lp/doc/I3lwnxdfGz , also here: http://tiny.cc/Valiente_AEiNBT
' {3} "Snap buckling, writhing and Loop formation In twisted rods" by V.G.A. GOSS, http://myweb.lsbu.ac.uk/~gossga/thesisFinal.pdf
' {4} "Theory of Elastic Stability" by Stephen Timoshenko, http://www.scribd.com/doc/50402462/Timoshenko-Theory-of-Elastic-Stability (start on p. 76)
'
' INPUT:
' PtA - First anchor point (required)
' PtB - Second anchor point (optional, though 2 out of the 4--length, width, height, angle--need to be specified)
' [note that PtB can be the same as PtA (meaning width would be zero)]
' [also note that if a different width is additionally specified that's not equal to the distance between PtA and PtB, then the end point will not equal PtB anymore]
' Pln - Plane of the bent rod/wire, which bends up in the +y direction. The line between PtA and PtB (if specified) must be parallel to the x-axis of this plane
'
' ** 2 of the following 4 need to be specified **
' Len - Length of the rod/wire, which needs to be > 0
' Wid - Width between the endpoints of the curve [note: if PtB is specified in addition, and distance between PtA and PtB <> width, the end point will be relocated
' Ht - Height of the bent rod/wire (when negative, curve will bend downward, relative to the input plane, instead)
' Ang - Inner departure angle or tangent angle (in radians) at the ends of the bent rod/wire. Set up so as width approaches length (thus height approaches zero), angle approaches zero
'
' * Following variables only needed for optional calculating of bending force, not for shape of curve.
' E - Young's modulus (modulus of elasticity) in GPa (=N/m^2) (material-specific. for example, 7075 aluminum is roughly 71.7 GPa)
' I - Second moment of area (or area moment of inertia) in m^4 (cross-section-specific. for example, a hollow rod
' would have I = pi * (outer_diameter^4 - inner_diameter^4) / 32
' Note: E*I is also known as flexural rigidity or bending stiffness
'
' OUTPUT:
' out - only for debugging messages
' Pts - the list of points that approximate the shape of the elastica
' Crv - the 3rd-degree curve interpolated from those points (with accurate start & end tangents)
' L - the length of the rod/wire
' W - the distance (width) between the endpoints of the rod/wire
' H - the height of the bent rod/wire
' A - the tangent angle at the (start) end of the rod/wire
' F - the force needed to hold the rod/wire in a specific shape (based on the material properties & cross-section) **be sure your units for 'I' match your units for the
' rest of your inputs (length, width, etc.). Also note that the critical buckling load (force) that makes the rod/wire start to bend can be found at height=0
'
' THANKS TO:
' Mårten Nettelbladt (thegeometryofbending.blogspot.com)
' Daniel Piker (Kangaroo plugin)
' David Rutten (Grasshopper guru)
' Euler & Bernoulli (the O.G.'s)
'
' -----------------------------------------------------------------
Dim ignoreSelfIntersecting As Boolean = False ' set to True if you don't want to output curves where width < 0, which creates a self-intersecting curve
Dim inCt As Integer = 0 ' count the number of required parameters that are receiving data
Dim length As Double
Dim width As System.Object = Nothing ' need to set as Nothing so we can check if it has been assigned a value later
Dim height As Double
Dim angle As Double
Dim m As Double
Dim multiple_m As New List(Of Double)
Dim AtoB As Line
Dim flip_H As Boolean = False ' if height is negative, this flag will be set
Dim flip_A As Boolean = False ' if angle is negative, this flag will be set
If Not IsSet("Pln") Then
Msg("error", "Base plane is not set")
Return
End If
If Not IsSet("PtA") Then
Msg("error", "Point A is not set")
Return
End If
If Math.Round(Pln.DistanceTo(PtA), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point A is not on the base plane")
Return
End If
Dim refPlane As Plane = Pln ' create a reference plane = input plane and set the origin of it to PtA in case PtA isn't the origin already
refPlane.Origin = PtA
If IsSet("PtB") Then
If Math.Round(Pln.DistanceTo(PtB), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point B is not on the base plane")
Return
End If
AtoB = New Line(PtA, PtB)
If AtoB.Length <> 0 And Not AtoB.Direction.IsPerpendicularTo(Pln.YAxis) Then
Msg("error", "The line between PtA and PtB is not perpendicular to the Y-axis of the specified plane")
Return
End If
inCt += 1
If IsSet("Wid") Then Msg("info", "Wid will override the distance between PtA and PtB. If you do not want this to happen, disconnect PtB or Wid.")
width = PtA.DistanceTo(PtB) ' get the width (distance) between PtA and PtB
Dim refPtB As Point3d
refPlane.RemapToPlaneSpace(PtB, refPtB)
If refPtB.X < 0 Then width = -width ' check if PtB is to the left of PtA...if so, width is negative
End If
If IsSet("Len") Then inCt += 1
If IsSet("Wid") Then inCt += 1
If IsSet("Ht") Then inCt += 1
If IsSet("Ang") Then inCt += 1
If inCt > 2 Then Msg("info", "More parameters set than are required (out of length, width, height, angle). Only using the first two valid ones.")
' check for connected/specified inputs. note: only the first two that it comes across will be used
If IsSet("Len") Then ' if length is specified then...
If Len <= 0 Then
Msg("error", "Length cannot be negative or zero")
Return
End If
If IsSet("Wid") Then ' find height & angle based on length and specified width
If Wid > Len Then
Msg("error", "Width is greater than length")
Return
End If
If Wid = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
width = Wid
Else
m = SolveMFromLenWid(Len, Wid)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
width = Wid
End If
Else If width IsNot Nothing Then ' find height & angle based on length and calculated width (distance between PtA and PtB)
If width > Len Then
Msg("error", "Width is greater than length")
Return
End If
If width = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
Else
m = SolveMFromLenWid(Len, width)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
Else If IsSet("Ht") Then ' find width & angle based on length and height ** possible to return 2 results **
If Math.Abs(Ht / Len) > Defined.MAX_HL_RATIO Then
Msg("error", "Height not possible with given length")
Return
End If
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
width = Len
angle = 0
Else
multiple_m = SolveMFromLenHt(Len, Ht) ' note that it's possible for two values of m to be found if height is close to max height
If multiple_m.Count = 1 Then ' if there's only one m value returned, calculate the width & angle here. we'll deal with multiple m values later
m = multiple_m.Item(0)
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
End If
height = Ht
Else If IsSet("Ang") Then ' find width & height based on length and angle
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
width = Len
height = 0
Else
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to length")
Return
End If
length = Len
Else If IsSet("Wid") Then ' if width is specified then...
If IsSet("Ht") Then ' find length & angle based on specified width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = Wid
angle = 0
Else
m = SolveMFromWidHt(Wid, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on specified width and angle
If Wid = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = Wid
height = 0
Else
length = Wid / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to width (Wid)")
Return
End If
width = Wid
Else If width IsNot Nothing Then ' if width is determined by PtA and PtB then...
If IsSet("Ht") Then ' find length & angle based on calculated width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = width
angle = 0
Else
m = SolveMFromWidHt(width, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on calculated width and angle
If width = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = width
height = 0
Else
length = width / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to PtA and PtB")
Return
End If
Else If IsSet("Ht") Then ' if height is specified then...
If IsSet("Ang") Then ' find length & width based on height and angle
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_H = True
flip_A = True
End If
If Ht = 0 Then
Msg("error", "Height can't = 0 if only height and angle are specified")
Return
Else
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = Not flip_A
flip_H = Not flip_H
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then
Msg("error", "Angle can't = 0 if only height and angle are specified")
Return
Else
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
width = Cal_W(length, m) ' L * (2 * E(m) / K(m) - 1)
End If
angle = Ang
End If
height = Ht
Else
Msg("error", "Need to specify one more parameter in addition to height")
Return
End If
Else If IsSet("Ang") Then
Msg("error", "Need to specify one more parameter in addition to angle")
Return
Else
Msg("error", "Need to specify two of the four parameters: length, width (or PtB), height, and angle")
Return
End If
If m > Defined.M_MAX Then
Msg("error", "Form of curve not solvable with current algorithm and given inputs")
Return
End If
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
If multiple_m.Count > 1 Then ' if there is more than one m value returned, calculate the width, angle, and curve for each
Dim multi_pts As New DataTree(Of Point3d)
Dim multi_crv As New List(Of Curve)
Dim tmp_pts As New List(Of Point3d)
Dim multi_W, multi_A, multi_F As New List(Of Double)
Dim j As Integer = 0 ' used for creating a new branch (GH_Path) for storing pts which is itself a list of points
For Each m_val As Double In multiple_m
width = Cal_W(length, m_val) 'length * (2 * EllipticE(m_val) / EllipticK(m_val) - 1)
If width < 0 And ignoreSelfIntersecting Then
Msg("warning", "One curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Continue For
End If
If m_val >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve whose width = " & Math.Round(width, 4) & " is not guaranteed")
angle = Cal_A(m_val) 'Math.Asin(2 * m_val - 1)
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
tmp_pts = FindBendForm(length, width, m_val, angle, refPlane)
multi_pts.AddRange(tmp_pts, New GH_Path(j))
multi_crv.Add(MakeCurve(tmp_pts, angle, refPlane))
multi_W.Add(width)
If flip_A Then angle = -angle
multi_A.Add(angle)
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
multi_F.Add(EllipticK(m_val) ^ 2 * E * I / length ^ 2) ' from reference {4} pg. 79
j += 1
refPlane.Origin = PtA ' reset the reference plane origin to PtA for the next m_val
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m_val & ", k=" & Math.Sqrt(m_val) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
Next
' assign the outputs
Pts = multi_pts
Crv = multi_crv
L = length
W = multi_W
If flip_H Then height = -height
H = height
A = multi_A
F = multi_F
Else ' only deal with the single m value
If m >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve at these parameters is not guaranteed")
If width < 0 And ignoreSelfIntersecting Then
Msg("error", "Curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Return
End If
Pts = FindBendForm(length, width, m, angle, refPlane)
Crv = MakeCurve(pts, angle, refPlane)
L = length
W = width
If flip_H Then height = -height
H = height
If flip_A Then angle = -angle
A = angle
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
F = EllipticK(m) ^ 2 * E * I / length ^ 2 ' from reference {4} pg. 79. Note: the critical buckling (that makes the rod/wire start to bend) can be found at height=0 (width=length)
'height = Math.Sqrt(((2 * Len / 5) ^ 2 - ((Wid - Len / 5) / 2) ^ 2) ' quick approximation discovered by Mårten of 'Geometry of Bending' fame ( http://tiny.cc/it2pbx )
'width = (Len +/- 2 * Math.Sqrt(4 * Len ^ 2 - 25 * Ht ^ 2)) / 5 ' derived from above
'length = (2 * Math.Sqrt(15 * Ht ^ 2 + 4 * Wid ^ 2) - Wid) / 3 ' derived from above
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m & ", k=" & Math.Sqrt(m) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
End If
-
2806
1380
84
184
-
2848
1472
- 9
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 8
- 3ede854e-c753-40eb-84cb-b48008f14fd4
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- true
- Script Variable PtA
- 89fe7d9c-b998-43b5-8788-30064fd07e47
- PtA
- PtA
- true
- 0
- true
- c54e879a-bb6c-47c6-b366-aaa5a16a426a
- 83dc0e24-1c12-445e-8647-dffc452baa6a
- 2
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
2808
1382
25
20
-
2822
1392
- true
- Script Variable PtB
- d6635d82-91c7-476c-acf5-3f2feae5d91b
- PtB
- PtB
- true
- 0
- true
- 72b7092f-b51c-4a8b-b457-5cc6f58de91d
- 5c0c8191-e5d5-44d8-9b74-ad7b50095c12
- 2
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
2808
1402
25
20
-
2822
1412
- true
- Script Variable Pln
- 8a5ea10d-8baa-47cd-8970-989b44d90853
- Pln
- Pln
- true
- 0
- true
- f5ef3118-8c76-4765-bdd9-16087c3ebb2d
- 1
- 3897522d-58e9-4d60-b38c-978ddacfedd8
-
2808
1422
25
20
-
2822
1432
- true
- Script Variable Len
- 4adfaa55-4523-43d7-9887-fcfc9daa5d32
- Len
- Len
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2808
1442
25
20
-
2822
1452
- true
- Script Variable Wid
- 8d352101-30bc-4590-8ef7-3bebef383668
- Wid
- Wid
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2808
1462
25
20
-
2822
1472
- true
- Script Variable Ht
- ed97f943-b85a-4bc0-84db-64b077475aca
- Ht
- Ht
- true
- 0
- true
- cd2f5af0-b741-48d5-8bbd-e9695d5278d8
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2808
1482
25
20
-
2822
1492
- true
- Script Variable Ang
- c30d75f7-bb99-4be5-88aa-f992b8386696
- Ang
- Ang
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2808
1502
25
20
-
2822
1512
- true
- Script Variable E
- 33bfc033-c0d3-4ebb-a5b0-659df3a0b51e
- E
- E
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2808
1522
25
20
-
2822
1532
- true
- Script Variable I
- 66f1e54b-d2c1-43dd-8716-e6fa7a1ddeca
- I
- I
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2808
1542
25
20
-
2822
1552
- 1
- Print, Reflect and Error streams
- be85f9e8-bde2-44f9-9bb8-80b1010c9d68
- out
- out
- false
- 0
-
2863
1382
25
22
-
2875.5
1393.25
- Output parameter Pts
- bacf233a-c717-41ce-b241-8552418f09f9
- Pts
- Pts
- false
- 0
-
2863
1404
25
23
-
2875.5
1415.75
- Output parameter Crv
- 4fa97325-f527-43c0-a006-78cf944c5e40
- Crv
- Crv
- false
- 0
-
2863
1427
25
22
-
2875.5
1438.25
- Output parameter L
- b9ed95d2-8f4a-49e9-a734-c73e21c200b4
- L
- L
- false
- 0
-
2863
1449
25
23
-
2875.5
1460.75
- Output parameter W
- 264cbae0-f043-490d-9121-0e45630a0b2f
- W
- W
- false
- 0
-
2863
1472
25
22
-
2875.5
1483.25
- Output parameter H
- 1578bf3a-8211-4a77-85d0-3cd951789283
- H
- H
- false
- 0
-
2863
1494
25
23
-
2875.5
1505.75
- Output parameter A
- 97c17859-cbbf-4962-a448-d8665c3e706a
- A
- A
- false
- 0
-
2863
1517
25
22
-
2875.5
1528.25
- Output parameter F
- 8f3ba33f-2383-4ae9-b911-b9b6e4553a35
- F
- F
- false
- 0
-
2863
1539
25
23
-
2875.5
1550.75
- c277f778-6fdf-4890-8f78-347efb23c406
- Pipe
- Create a pipe surface around a rail curve.
- a18b4542-f317-4532-9634-9ef245df4e2c
- Pipe
- Pipe
-
3076
1319
64
64
-
3107
1351
- Base curve
- 9be76020-39f2-465f-b508-f09d3f48a425
- Curve
- C
- false
- 4fa97325-f527-43c0-a006-78cf944c5e40
- 1
-
3078
1321
14
20
-
3086.5
1331
- Pipe radius
- 0f317bff-3048-480b-865a-13a2e1cb5106
- Radius
- R
- false
- f2abb0db-802c-4f59-83cb-393711b4a3d9
- 1
-
3078
1341
14
20
-
3086.5
1351
- 1
- 1
- {0}
- 1
- Specifies the type of caps (0=None, 1=Flat, 2=Round)
- 38981e04-97f9-4736-a46b-c55825f5b8fe
- Caps
- E
- false
- 0
-
3078
1361
14
20
-
3086.5
1371
- 1
- 1
- {0}
- 0
- 1
- Resulting Pipe
- d118f269-0338-4d1d-b06d-018819a25f1a
- Pipe
- P
- false
- 0
-
3122
1321
16
60
-
3130
1351
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- f2abb0db-802c-4f59-83cb-393711b4a3d9
- Panel
- false
- 0
- 0
- .25
-
2955
1314
50
20
- 0
- 0
- 0
-
2955.289
1314.952
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 26ed0e55-cf0a-436e-9447-805704984e62
- Panel
- false
- 0
- 087cd096-ba72-4a81-a462-a9ce3ce43ec4
- 1
- Double click to edit panel content…
-
3045
1553
105
55
- 0
- 0
- 0
-
3045.485
1553.607
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 0d77c51e-584f-44e8-aed2-c2ddf4803888
- Degrees
- Convert an angle specified in radians to degrees
- bb620c76-8624-412c-8f17-4aa82e09f1b9
- Degrees
- Deg
-
2955
1562
64
28
-
2985
1576
- Angle in radians
- e10ae9f2-834e-4fd3-afbb-6416a8f9ca28
- Radians
- R
- false
- 97c17859-cbbf-4962-a448-d8665c3e706a
- 1
-
2957
1564
13
24
-
2965
1576
- Angle in degrees
- 087cd096-ba72-4a81-a462-a9ce3ce43ec4
- Degrees
- D
- false
- 0
-
3000
1564
17
24
-
3008.5
1576
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 4ddb17a4-9e5f-4fb4-9f06-84399d240517
- Panel
- false
- 0
- b9ed95d2-8f4a-49e9-a734-c73e21c200b4
- 1
- Double click to edit panel content…
-
2941
1424
97
54
- 0
- 0
- 0
-
2941.968
1424.592
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 97a1d833-23ef-4dd7-a8f6-0467955bf4f5
- Panel
- false
- 0
- 264cbae0-f043-490d-9121-0e45630a0b2f
- 1
- Double click to edit panel content…
-
3053
1458
105
55
- 0
- 0
- 0
-
3053.527
1458.041
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 8e36a5c6-61f4-4366-8856-2c787fd9a806
- Panel
- false
- 0
- 1578bf3a-8211-4a77-85d0-3cd951789283
- 1
- Double click to edit panel content…
-
2941
1493
97
55
- 0
- 0
- 0
-
2941.552
1493.67
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 0903a6c2-e102-41a9-8326-3f9533f91f9f
- Panel
- false
- 0
- 0
- -150
-
1440
1185
50
20
- 0
- 0
- 0
-
1440.106
1185.658
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 17a61eca-a95a-4f8b-aa55-052523e686bc
- Panel
- false
- 0
- 0
- 150
-
1441
1215
50
20
- 0
- 0
- 0
-
1441.106
1215.658
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- d1a28e95-cf96-4936-bf34-8bf142d731bf
- Construct Domain
- Create a numeric domain from two numeric extremes.
- 14534673-98f6-45e8-b11f-39da628bc4ca
- Construct Domain
- Dom
-
2193
764
61
44
-
2224
786
- Start value of numeric domain
- c60598bb-4ac8-4310-9f9f-0d75cea21cfe
- Domain start
- A
- false
- 64b83d9b-5ae1-4022-b79e-c9135d3cdfc6
- 1
-
2195
766
14
20
-
2203.5
776
- 1
- 1
- {0}
- 0
- End value of numeric domain
- c4f2cdcf-3ac3-420a-925f-c2653c042270
- Domain end
- B
- false
- 2398bd00-b514-4723-b31f-c436e1ae908b
- 1
-
2195
786
14
20
-
2203.5
796
- 1
- 1
- {0}
- 1
- Numeric domain between {A} and {B}
- 035d494c-d9fa-434d-874c-206716be82af
- Domain
- I
- false
- 0
-
2239
766
13
40
-
2245.5
786
- 9445ca40-cc73-4861-a455-146308676855
- Range
- Create a range of numbers.
- fbb4ab09-bb2a-42d6-a9a9-345b5f2473bc
- Range
- Range
-
2295
775
64
44
-
2326
797
- Domain of numeric range
- 0dd6e136-7641-43ed-94ff-d87c8b3a4a7f
- Domain
- D
- false
- 035d494c-d9fa-434d-874c-206716be82af
- 1
-
2297
777
14
20
-
2305.5
787
- 1
- 1
- {0}
-
0
1
- Number of steps
- b991e2eb-aa24-4a37-b83b-4de89b217793
- Steps
- N
- false
- cc8db470-d2c6-4bbc-92b0-9305165143f7
- 1
-
2297
797
14
20
-
2305.5
807
- 1
- 1
- {0}
- 10
- 1
- Range of numbers
- 9b2fc3d6-5abb-46f8-a49e-0ae9e8dc1647
- Range
- R
- false
- 0
-
2341
777
16
40
-
2349
797
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- cc8db470-d2c6-4bbc-92b0-9305165143f7
- Number Slider
- num curves
- false
- 0
-
1969
831
284
20
-
1969.186
831.0843
- 0
- 1
- 0
- 400
- 1
- 0
- 200
- 079bd9bd-54a0-41d4-98af-db999015f63d
- VB Script
- Private Function IsSet(ByVal param As String) As Boolean ' Check if an input parameter has data
Dim i As Integer = Component.Params.IndexOfInputParam(param)
If i > -1 Then
Return Component.Params.Input.ElementAt(i).DataType > 1 ' input parameter DataType of 1 means it's not receiving input (internal or external)
Else
Msg("error", "Input parameter '" & param & "' not found")
Return False
End If
End Function
Private Sub Msg(ByVal type As String, ByVal msg As String) ' Output an error, warning, or informational message
Select Case type
Case "error"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, msg)
Print("Error: " & msg)
Case "warning"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, msg)
Print("Warning: " & msg)
Case "info"
Component.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, msg)
Print(msg)
End Select
End Sub
' Solve for the m parameter from length and width (reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m))
Private Function SolveMFromLenWid(ByVal L As Double, ByVal w As Double) As Double
If w = 0 Then
Return Defined.M_ZERO_W ' for the boundry condition width = 0, bypass the function and return the known m value
End If
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwl As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwl = 2 * EllipticE(m) / EllipticK(m) - 1 ' calculate w/L with the test value of m
If cwl < w / L Then ' compares the calculated w/L with the actual w/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Solve for the m parameter from length and height (reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m))
' Note that it's actually possible to find 2 valid values for m (hence 2 width values) at certain height values
Private Function SolveMFromLenHt(ByVal L As Double, ByVal h As Double) As List(Of Double)
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim twoWidths As Boolean = h / L >= Defined.DOUBLE_W_HL_RATIO And h / L < Defined.MAX_HL_RATIO ' check to see if h/L is within the range where 2 solutions for the width are possible
Dim m As Double
Dim mult_m As New List(Of Double)
Dim chl As Double
If twoWidths Then
' find the first of two possible solutions for m with the following limits:
lower = Defined.M_DOUBLE_W ' see constants at bottom of script
upper = Defined.M_MAXHEIGHT ' see constants at bottom of script
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
' then find the second of two possible solutions for m with the following limits:
lower = Defined.M_MAXHEIGHT ' see constants at bottom of script
upper = 1
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl < h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
If m <= Defined.M_MAX Then ' return this m parameter only if it falls within the maximum useful value (above which the curve breaks down)
mult_m.Add(m)
End If
Else
' find the one possible solution for the m parameter
upper = Defined.M_DOUBLE_W ' limit the upper end of the search to the maximum value of m for which only one solution exists
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
chl = Math.Sqrt(m) / EllipticK(m) ' calculate h/L with the test value of m
If chl > h / L Then ' compares the calculated h/L with the actual h/L then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
mult_m.Add(m)
End If
Return mult_m
End Function
' Solve for the m parameter from width and height (derived from reference {1} equations (33) and (34) with same notes as above)
Private Function SolveMFromWidHt(ByVal w As Double, ByVal h As Double) As Double
Dim n As Integer = 1 ' Iteration counter (quit if >MAXIT)
Dim lower As Double = 0 ' m must be within this range
Dim upper As Double = 1
Dim m As Double
Dim cwh As Double
Do While (upper - lower) > Defined.MAXERR AndAlso (n) < Defined.MAXIT ' Repeat until range narrow enough or MAXIT
m = (upper + lower) / 2
cwh = (2 * EllipticE(m) - EllipticK(m)) / Math.Sqrt(m) ' calculate w/h with the test value of m
If cwh < w / h Then ' compares the calculated w/h with the actual w/h then narrows the range of possible m
upper = m
Else
lower = m
End If
n += 1
Loop
Return m
End Function
' Calculate length based on height and an m parameter, derived from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_L(ByVal h As Double, ByVal m As Double) As Double
Return h * EllipticK(m) / Math.Sqrt(m)
End Function
' Calculate width based on length and an m parameter, derived from reference {1} equation (34), except b = width and K(k) and E(k) should be K(m) and E(m)
Private Function Cal_W(ByVal L As Double, ByVal m As Double) As Double
Return L * (2 * EllipticE(m) / EllipticK(m) - 1)
End Function
' Calculate height based on length and an m parameter, from reference {1} equation (33), except K(k) should be K(m) and k = sqrt(m)
Private Function Cal_H(ByVal L As Double, ByVal m As Double) As Double
Return L * Math.Sqrt(m) / EllipticK(m)
End Function
' Calculate the unique m parameter based on a start tangent angle, from reference {2}, just above equation (9a), that states k = Sin(angle / 2 + Pi / 4),
' but as m = k^2 and due to this script's need for an angle rotated 90° versus the one in reference {1}, the following formula is the result
' New note: verified by reference {4}, pg. 78 at the bottom
Private Function Cal_M(ByVal a As Double) As Double
Return (1 - Math.Cos(a)) / 2 ' equal to Sin^2(a/2) too
End Function
' Calculate start tangent angle based on an m parameter, derived from above formula
Private Function Cal_A(ByVal m As Double) As Double
Return Math.Acos(1 - 2 * m)
End Function
' This is the heart of this script, taking the found (or specified) length, width, and angle values along with the found m parameter to create
' a list of points that approximate the shape or form of the elastica. It works by finding the x and y coordinates (which are reversed versus
' the original equations (12a) and (12b) from reference {2} due to the 90° difference in orientation) based on the tangent angle along the curve.
' See reference {2} for more details on how they derived it. Note that to simplify things, the algorithm only calculates the points for half of the
' curve, then mirrors those points along the y-axis.
Private Function FindBendForm(ByVal L As Double, ByVal w As Double, ByVal m As Double, ByVal ang As Double, ByVal refPln As Plane) As List(Of Point3d)
L = L / 2 ' because the below algorithm is based on the formulas in reference {2} for only half of the curve
w = w / 2 ' same
If ang = 0 Then ' if angle (and height) = 0, then simply return the start and end points of the straight line
Dim out As New List(Of Point3d)
out.Add(refPln.PointAt(w, 0, 0))
out.Add(refPln.PointAt(-w, 0, 0))
Return out
End If
Dim x As Double
Dim y As Double
Dim halfCurvePts As New List(Of Point3d)
Dim fullCurvePts As New List(Of Point3d)
Dim translatedPts As New List(Of Point3d)
ang -= Math.PI / 2 ' a hack to allow this algorithm to work, since the original curve in paper {2} was rotated 90°
Dim angB As Double = ang + (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' angB is the 'lowercase theta' which should be in formula {2}(12b) as the interval
' start [a typo...see equation(3)]. It's necessary to start angB at ang + [interval] instead of just ang due to integration failing at angB = ang
halfCurvePts.Add(New Point3d(w, 0, 0)) ' start with this known initial point, as integration will fail when angB = ang
' each point {x, y} is calculated from the tangent angle, angB, that occurs at each point (which is why this iterates from ~ang to -pi/2, the known end condition)
Do While Math.Round(angB, Defined.ROUNDTO) >= Math.Round(-Math.PI / 2, Defined.ROUNDTO)
y = (Math.Sqrt(2) * Math.Sqrt(Math.Sin(ang) - Math.Sin(angB)) * (w + L)) / (2 * EllipticE(m)) ' note that x and y are swapped vs. (12a) and (12b)
x = (L / (Math.Sqrt(2) * EllipticK(m))) * Simpson(angB, -Math.PI / 2, 500, ang) ' calculate the Simpson approximation of the integral (function f below)
' over the interval angB ('lowercase theta') to -pi/2. side note: is 500 too few iterations for the Simson algorithm?
If Math.Round(x, Defined.ROUNDTO) = 0 Then x = 0
halfCurvePts.Add(New Point3d(x, y, 0))
angB += (-Math.PI / 2 - ang) / Defined.CURVEDIVS ' onto the next tangent angle
Loop
' After finding the x and y values for half of the curve, add the {-x, y} values for the rest of the curve
For Each point As Point3d In halfCurvePts
If Math.Round(point.X, Defined.ROUNDTO) = 0 Then
If Math.Round(point.Y, Defined.ROUNDTO) = 0 Then
fullCurvePts.Add(New Point3d(0, 0, 0)) ' special case when width = 0: when x = 0, only duplicate the point when y = 0 too
End If
Else
fullCurvePts.Add(New Point3d(-point.X, point.Y, 0))
End If
Next
halfCurvePts.Reverse
fullCurvePts.AddRange(halfCurvePts)
For Each p As Point3d In fullCurvePts
translatedPts.Add(refPln.PointAt(p.X, p.Y, p.Z)) ' translate the points from the reference plane to the world plane
Next
Return translatedPts
End Function
' Interpolates the points from FindBendForm to create the Elastica curve. Uses start & end tangents for greater accuracy.
Private Function MakeCurve(ByVal pts As List(Of Point3d), ByVal ang As Double, ByVal refPln As Plane) As Curve
If ang <> 0 Then
Dim ts, te As New Vector3d(refPln.XAxis)
ts.Rotate(ang, refPln.ZAxis)
te.Rotate(-ang, refPln.ZAxis)
Return Curve.CreateInterpolatedCurve(pts, 3, CurveKnotStyle.Chord, ts, te) ' 3rd degree curve with 'Chord' Knot Style
Else
Return Curve.CreateInterpolatedCurve(pts, 3) ' if angle (and height) = 0, then simply interpolate the straight line (no start/end tangents)
End If
End Function
' Implements the Simpson approximation for an integral of function f below
Public Function Simpson(a As Double, b As Double, n As Integer, theta As Double) As Double 'n should be an even number
Dim j As Integer, s1 As Double, s2 As Double, h As Double
h = (b - a) / n
s1 = 0
s2 = 0
For j = 1 To n - 1 Step 2
s1 = s1 + fn(a + j * h, theta)
Next j
For j = 2 To n - 2 Step 2
s2 = s2 + fn(a + j * h, theta)
Next j
Simpson = h / 3 * (fn(a, theta) + 4 * s1 + 2 * s2 + fn(b, theta))
End Function
' Specific calculation for the above integration
Public Function fn(x As Double, theta As Double) As Double
fn = Math.Sin(x) / (Math.Sqrt(Math.Sin(theta) - Math.Sin(x))) ' from reference {2} formula (12b)
End Function
' Return the Complete Elliptic integral of the 1st kind
' Abramowitz and Stegun p.591, formula 17.3.11
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticK(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum += Math.Pow(m, i) * Math.Pow(term, 2)
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
' Return the Complete Elliptic integral of the 2nd kind
' Abramowitz and Stegun p.591, formula 17.3.12
' Code from http://www.codeproject.com/Articles/566614/Elliptic-integrals
Public Function EllipticE(ByVal m As Double) As Double
Dim sum, term, above, below As Double
sum = 1
term = 1
above = 1
below = 2
For i As Integer = 1 To 100
term *= above / below
sum -= Math.Pow(m, i) * Math.Pow(term, 2) / above
above += 2
below += 2
Next
sum *= 0.5 * Math.PI
Return sum
End Function
Friend Partial NotInheritable Class Defined
Private Sub New()
End Sub
' Note: most of these values for m and h/L ratio were found with Wolfram Alpha and either specific intercepts (x=0) or local minima/maxima. They should be constant.
Public Const M_SKETCHY As Double = 0.95 ' value of the m parameter where the curvature near the ends of the curve gets wonky
Public Const M_MAX As Double = 0.993 ' maximum useful value of the m parameter, above which this algorithm for the form of the curve breaks down
Public Const M_ZERO_W As Double = 0.826114765984970336 ' value of the m parameter when width = 0
Public Const M_MAXHEIGHT As Double = 0.701327460663101223 ' value of the m parameter at maximum possible height of the bent rod/wire
Public Const M_DOUBLE_W As Double = 0.180254422335013983 ' minimum value of the m parameter when two width values are possible for a given height and length
Public Const DOUBLE_W_HL_RATIO As Double = 0.257342117984635757 ' value of the height/length ratio above which there are two possible width values
Public Const MAX_HL_RATIO As Double = 0.403140189705650243 ' maximum possible value of the height/length ratio
Public Const MAXERR As Double = 0.0000000001 ' error tolerance
Public Const MAXIT As Integer = 100 ' maximum number of iterations
Public Const ROUNDTO As Integer = 10 ' number of decimal places to round off to
Public Const CURVEDIVS As Integer = 50 ' number of sample points for building the curve (or half-curve as it were)
End Class
- A VB.NET scriptable component
-
98
86
- true
- 63218c71-7758-4168-b163-745e456fb525
- VB Script
- VB
- true
- 0
- ' -----------------------------------------------------------------
' Elastic Bending Script by Will McElwain
' Created February 2014
'
' DESCRIPTION:
' This beast creates the so-called 'elastica curve', the shape a long, thin rod or wire makes when it is bent elastically (i.e. not permanently). In this case, force
' is assumed to only be applied horizontally (which would be in line with the rod at rest) and both ends are assumed to be pinned or hinged meaning they are free
' to rotate (as opposed to clamped, when the end tangent angle is fixed, usually horizontally). An interesting finding is that it doesn't matter what the material or
' cross-sectional area is, as long as they're uniform along the entire length. Everything makes the same shape when bent as long as it doesn't cross the threshold
' from elastic to plastic (permanent) deformation (I don't bother to find that limit here, but can be found if the yield stress for a material is known).
'
' Key to the formulas used in this script are elliptic integrals, specifically K(m), the complete elliptic integral of the first kind, and E(m), the complete elliptic
' integral of the second kind. There was a lot of confusion over the 'm' and 'k' parameters for these functions, as some people use them interchangeably, but they are
' not the same. m = k^2 (thus k = Sqrt(m)). I try to use the 'm' parameter exclusively to avoid this confusion. Note that there is a unique 'm' parameter for every
' configuration/shape of the elastica curve.
'
' This script tries to find that unique 'm' parameter based on the inputs. The algorithm starts with a test version of m, evaluates an expression, say 2*E(m)/K(m)-1,
' then compares the result to what it should be (in this case, a known width/length ratio). Iterate until the correct m is found. Once we have m, we can then calculate
' all of the other unknowns, then find points that lie on that curve, then interpolate those points for the actual curve. You can also use Wolfram|Alpha as I did to
' find the m parameter based on the equations in this script (example here: http://tiny.cc/t4tpbx for when say width=45.2 and length=67.1).
'
' Other notes:
' * This script works with negative values for width, which will creat a self-intersecting curve (as it should). The curvature of the elastica starts to break down around
' m=0.95 (~154°), but this script will continue to work until M_MAX, m=0.993 (~169°). If you wish to ignore self-intersecting curves, set ignoreSelfIntersecting to True
' * When the only known values are length and height, it is actually possible for certain ratios of height to length to have two valid m values (thus 2 possible widths
' and angles). This script will return them both.
' * Only the first two valid parameters (of the required ones) will be used, meaning if all four are connected (length, width or a PtB, height, and angle), this script will
' only use length and width (or a PtB).
' * Depending on the magnitude of your inputs (say if they're really small, like if length < 10), you might have to increase the constant ROUNDTO at the bottom
'
' REFERENCES:
' {1} "The elastic rod" by M.E. Pacheco Q. & E. Pina, http://www.scielo.org.mx/pdf/rmfe/v53n2/v53n2a8.pdf
' {2} "An experiment in nonlinear beam theory" by A. Valiente, http://www.deepdyve.com/lp/doc/I3lwnxdfGz , also here: http://tiny.cc/Valiente_AEiNBT
' {3} "Snap buckling, writhing and Loop formation In twisted rods" by V.G.A. GOSS, http://myweb.lsbu.ac.uk/~gossga/thesisFinal.pdf
' {4} "Theory of Elastic Stability" by Stephen Timoshenko, http://www.scribd.com/doc/50402462/Timoshenko-Theory-of-Elastic-Stability (start on p. 76)
'
' INPUT:
' PtA - First anchor point (required)
' PtB - Second anchor point (optional, though 2 out of the 4--length, width, height, angle--need to be specified)
' [note that PtB can be the same as PtA (meaning width would be zero)]
' [also note that if a different width is additionally specified that's not equal to the distance between PtA and PtB, then the end point will not equal PtB anymore]
' Pln - Plane of the bent rod/wire, which bends up in the +y direction. The line between PtA and PtB (if specified) must be parallel to the x-axis of this plane
'
' ** 2 of the following 4 need to be specified **
' Len - Length of the rod/wire, which needs to be > 0
' Wid - Width between the endpoints of the curve [note: if PtB is specified in addition, and distance between PtA and PtB <> width, the end point will be relocated
' Ht - Height of the bent rod/wire (when negative, curve will bend downward, relative to the input plane, instead)
' Ang - Inner departure angle or tangent angle (in radians) at the ends of the bent rod/wire. Set up so as width approaches length (thus height approaches zero), angle approaches zero
'
' * Following variables only needed for optional calculating of bending force, not for shape of curve.
' E - Young's modulus (modulus of elasticity) in GPa (=N/m^2) (material-specific. for example, 7075 aluminum is roughly 71.7 GPa)
' I - Second moment of area (or area moment of inertia) in m^4 (cross-section-specific. for example, a hollow rod
' would have I = pi * (outer_diameter^4 - inner_diameter^4) / 32
' Note: E*I is also known as flexural rigidity or bending stiffness
'
' OUTPUT:
' out - only for debugging messages
' Pts - the list of points that approximate the shape of the elastica
' Crv - the 3rd-degree curve interpolated from those points (with accurate start & end tangents)
' L - the length of the rod/wire
' W - the distance (width) between the endpoints of the rod/wire
' H - the height of the bent rod/wire
' A - the tangent angle at the (start) end of the rod/wire
' F - the force needed to hold the rod/wire in a specific shape (based on the material properties & cross-section) **be sure your units for 'I' match your units for the
' rest of your inputs (length, width, etc.). Also note that the critical buckling load (force) that makes the rod/wire start to bend can be found at height=0
'
' THANKS TO:
' Mårten Nettelbladt (thegeometryofbending.blogspot.com)
' Daniel Piker (Kangaroo plugin)
' David Rutten (Grasshopper guru)
' Euler & Bernoulli (the O.G.'s)
'
' -----------------------------------------------------------------
Dim ignoreSelfIntersecting As Boolean = False ' set to True if you don't want to output curves where width < 0, which creates a self-intersecting curve
Dim inCt As Integer = 0 ' count the number of required parameters that are receiving data
Dim length As Double
Dim width As System.Object = Nothing ' need to set as Nothing so we can check if it has been assigned a value later
Dim height As Double
Dim angle As Double
Dim m As Double
Dim multiple_m As New List(Of Double)
Dim AtoB As Line
Dim flip_H As Boolean = False ' if height is negative, this flag will be set
Dim flip_A As Boolean = False ' if angle is negative, this flag will be set
If Not IsSet("Pln") Then
Msg("error", "Base plane is not set")
Return
End If
If Not IsSet("PtA") Then
Msg("error", "Point A is not set")
Return
End If
If Math.Round(Pln.DistanceTo(PtA), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point A is not on the base plane")
Return
End If
Dim refPlane As Plane = Pln ' create a reference plane = input plane and set the origin of it to PtA in case PtA isn't the origin already
refPlane.Origin = PtA
If IsSet("PtB") Then
If Math.Round(Pln.DistanceTo(PtB), Defined.ROUNDTO) <> 0 Then
Msg("error", "Point B is not on the base plane")
Return
End If
AtoB = New Line(PtA, PtB)
If AtoB.Length <> 0 And Not AtoB.Direction.IsPerpendicularTo(Pln.YAxis) Then
Msg("error", "The line between PtA and PtB is not perpendicular to the Y-axis of the specified plane")
Return
End If
inCt += 1
If IsSet("Wid") Then Msg("info", "Wid will override the distance between PtA and PtB. If you do not want this to happen, disconnect PtB or Wid.")
width = PtA.DistanceTo(PtB) ' get the width (distance) between PtA and PtB
Dim refPtB As Point3d
refPlane.RemapToPlaneSpace(PtB, refPtB)
If refPtB.X < 0 Then width = -width ' check if PtB is to the left of PtA...if so, width is negative
End If
If IsSet("Len") Then inCt += 1
If IsSet("Wid") Then inCt += 1
If IsSet("Ht") Then inCt += 1
If IsSet("Ang") Then inCt += 1
If inCt > 2 Then Msg("info", "More parameters set than are required (out of length, width, height, angle). Only using the first two valid ones.")
' check for connected/specified inputs. note: only the first two that it comes across will be used
If IsSet("Len") Then ' if length is specified then...
If Len <= 0 Then
Msg("error", "Length cannot be negative or zero")
Return
End If
If IsSet("Wid") Then ' find height & angle based on length and specified width
If Wid > Len Then
Msg("error", "Width is greater than length")
Return
End If
If Wid = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
width = Wid
Else
m = SolveMFromLenWid(Len, Wid)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
width = Wid
End If
Else If width IsNot Nothing Then ' find height & angle based on length and calculated width (distance between PtA and PtB)
If width > Len Then
Msg("error", "Width is greater than length")
Return
End If
If width = Len Then ' skip the solver and set the known values
height = 0
m = 0
angle = 0
Else
m = SolveMFromLenWid(Len, width)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
Else If IsSet("Ht") Then ' find width & angle based on length and height ** possible to return 2 results **
If Math.Abs(Ht / Len) > Defined.MAX_HL_RATIO Then
Msg("error", "Height not possible with given length")
Return
End If
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
width = Len
angle = 0
Else
multiple_m = SolveMFromLenHt(Len, Ht) ' note that it's possible for two values of m to be found if height is close to max height
If multiple_m.Count = 1 Then ' if there's only one m value returned, calculate the width & angle here. we'll deal with multiple m values later
m = multiple_m.Item(0)
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
End If
height = Ht
Else If IsSet("Ang") Then ' find width & height based on length and angle
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
width = Len
height = 0
Else
width = Cal_W(Len, m) ' L * (2 * E(m) / K(m) - 1)
height = Cal_H(Len, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to length")
Return
End If
length = Len
Else If IsSet("Wid") Then ' if width is specified then...
If IsSet("Ht") Then ' find length & angle based on specified width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = Wid
angle = 0
Else
m = SolveMFromWidHt(Wid, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on specified width and angle
If Wid = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = Wid
height = 0
Else
length = Wid / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to width (Wid)")
Return
End If
width = Wid
Else If width IsNot Nothing Then ' if width is determined by PtA and PtB then...
If IsSet("Ht") Then ' find length & angle based on calculated width and height
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
If Ht = 0 Then ' skip the solver and set the known values
length = width
angle = 0
Else
m = SolveMFromWidHt(width, Ht)
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
angle = Cal_A(m) ' Acos(1 - 2 * m)
End If
height = Ht
Else If IsSet("Ang") Then ' find length & height based on calculated width and angle
If width = 0 Then
Msg("error", "Curve not possible with width = 0 and an angle as inputs")
Return
End If
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = True
flip_H = True
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then ' skip the solver and set the known values
length = width
height = 0
Else
length = width / (2 * EllipticE(m) / EllipticK(m) - 1)
If length < 0 Then
Msg("error", "Curve not possible at specified width and angle (calculated length is negative)")
Return
End If
height = Cal_H(length, m) ' L * Sqrt(m) / K(m)
End If
angle = Ang
Else
Msg("error", "Need to specify one more parameter in addition to PtA and PtB")
Return
End If
Else If IsSet("Ht") Then ' if height is specified then...
If IsSet("Ang") Then ' find length & width based on height and angle
If Ht < 0 Then
Ht = -Ht ' if height is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_H = True
flip_A = True
End If
If Ht = 0 Then
Msg("error", "Height can't = 0 if only height and angle are specified")
Return
Else
If Ang < 0 Then
Ang = -Ang ' if angle is negative, set it to positive (for the calculations) but flip the reference plane about its x-axis
refPlane.Transform(Transform.Mirror(New Plane(refPlane.Origin, refPlane.XAxis, refPlane.ZAxis)))
flip_A = Not flip_A
flip_H = Not flip_H
End If
m = Cal_M(Ang) ' (1 - Cos(a)) / 2
If Ang = 0 Then
Msg("error", "Angle can't = 0 if only height and angle are specified")
Return
Else
length = Cal_L(Ht, m) ' h * K(m) / Sqrt(m)
width = Cal_W(length, m) ' L * (2 * E(m) / K(m) - 1)
End If
angle = Ang
End If
height = Ht
Else
Msg("error", "Need to specify one more parameter in addition to height")
Return
End If
Else If IsSet("Ang") Then
Msg("error", "Need to specify one more parameter in addition to angle")
Return
Else
Msg("error", "Need to specify two of the four parameters: length, width (or PtB), height, and angle")
Return
End If
If m > Defined.M_MAX Then
Msg("error", "Form of curve not solvable with current algorithm and given inputs")
Return
End If
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
If multiple_m.Count > 1 Then ' if there is more than one m value returned, calculate the width, angle, and curve for each
Dim multi_pts As New DataTree(Of Point3d)
Dim multi_crv As New List(Of Curve)
Dim tmp_pts As New List(Of Point3d)
Dim multi_W, multi_A, multi_F As New List(Of Double)
Dim j As Integer = 0 ' used for creating a new branch (GH_Path) for storing pts which is itself a list of points
For Each m_val As Double In multiple_m
width = Cal_W(length, m_val) 'length * (2 * EllipticE(m_val) / EllipticK(m_val) - 1)
If width < 0 And ignoreSelfIntersecting Then
Msg("warning", "One curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Continue For
End If
If m_val >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve whose width = " & Math.Round(width, 4) & " is not guaranteed")
angle = Cal_A(m_val) 'Math.Asin(2 * m_val - 1)
refPlane.Origin = refPlane.PointAt(width / 2, 0, 0) ' adjust the origin of the reference plane so that the curve is centered about the y-axis (start of the curve is at x = -width/2)
tmp_pts = FindBendForm(length, width, m_val, angle, refPlane)
multi_pts.AddRange(tmp_pts, New GH_Path(j))
multi_crv.Add(MakeCurve(tmp_pts, angle, refPlane))
multi_W.Add(width)
If flip_A Then angle = -angle
multi_A.Add(angle)
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
multi_F.Add(EllipticK(m_val) ^ 2 * E * I / length ^ 2) ' from reference {4} pg. 79
j += 1
refPlane.Origin = PtA ' reset the reference plane origin to PtA for the next m_val
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m_val & ", k=" & Math.Sqrt(m_val) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
Next
' assign the outputs
Pts = multi_pts
Crv = multi_crv
L = length
W = multi_W
If flip_H Then height = -height
H = height
A = multi_A
F = multi_F
Else ' only deal with the single m value
If m >= Defined.M_SKETCHY Then Msg("info", "Accuracy of the curve at these parameters is not guaranteed")
If width < 0 And ignoreSelfIntersecting Then
Msg("error", "Curve is self-intersecting. To enable these, set ignoreSelfIntersecting to False")
Return
End If
Pts = FindBendForm(length, width, m, angle, refPlane)
Crv = MakeCurve(pts, angle, refPlane)
L = length
W = width
If flip_H Then height = -height
H = height
If flip_A Then angle = -angle
A = angle
E = E * 10 ^ 9 ' Young's modulus input E is in GPa, so we convert to Pa here (= N/m^2)
F = EllipticK(m) ^ 2 * E * I / length ^ 2 ' from reference {4} pg. 79. Note: the critical buckling (that makes the rod/wire start to bend) can be found at height=0 (width=length)
'height = Math.Sqrt(((2 * Len / 5) ^ 2 - ((Wid - Len / 5) / 2) ^ 2) ' quick approximation discovered by Mårten of 'Geometry of Bending' fame ( http://tiny.cc/it2pbx )
'width = (Len +/- 2 * Math.Sqrt(4 * Len ^ 2 - 25 * Ht ^ 2)) / 5 ' derived from above
'length = (2 * Math.Sqrt(15 * Ht ^ 2 + 4 * Wid ^ 2) - Wid) / 3 ' derived from above
'Print("length=" & length & ", width=" & width & ", height=" & height & ", angle=" & angle & ", m=" & m & ", k=" & Math.Sqrt(m) & ", w/L=" & width / length & ", h/L=" & height / length & ", w/h=" & width / height)
End If
-
2397
703
84
184
-
2439
795
- 9
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2
- 8
- 3ede854e-c753-40eb-84cb-b48008f14fd4
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- 8ec86459-bf01-4409-baee-174d0d2b13d0
- true
- Script Variable PtA
- c36c2a91-b586-4100-a3d3-5bbd29795b28
- PtA
- PtA
- true
- 0
- true
- 75154365-a588-4c21-86a3-ce81e626861d
- 1
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
2399
705
25
20
-
2413
715
- true
- Script Variable PtB
- c03912a8-42cd-4a8e-b0e4-d859c1258a99
- PtB
- PtB
- true
- 0
- true
- 0
- e1937b56-b1da-4c12-8bd8-e34ee81746ef
-
2399
725
25
20
-
2413
735
- true
- Script Variable Pln
- f51b86ed-0366-4427-847a-63fd2fd6bf90
- Pln
- Pln
- true
- 0
- true
- f3933593-ac71-4dcf-9de1-01828b79508a
- 1
- 3897522d-58e9-4d60-b38c-978ddacfedd8
-
2399
745
25
20
-
2413
755
- true
- Script Variable Len
- 7ea941b6-d28a-421f-a3f1-b6ee6ba45ce3
- Len
- Len
- true
- 0
- true
- 2398bd00-b514-4723-b31f-c436e1ae908b
- 1
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2399
765
25
20
-
2413
775
- true
- Script Variable Wid
- ca56b21d-1bf4-4ef7-9aba-89e8c40123e1
- Wid
- Wid
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2399
785
25
20
-
2413
795
- true
- Script Variable Ht
- 01f793d6-6952-4cc0-9007-804b34e3573a
- Ht
- Ht
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2399
805
25
20
-
2413
815
- true
- Script Variable Ang
- d1ecc6ce-5745-410a-98ac-8cd99da220f9
- Ang
- Ang
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2399
825
25
20
-
2413
835
- true
- Script Variable E
- ee84edc7-8985-4013-a1da-ab406c4a251b
- E
- E
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2399
845
25
20
-
2413
855
- true
- Script Variable I
- 06df9652-281a-4459-91a6-57c181550607
- I
- I
- true
- 0
- true
- 0
- 8e991e99-5fb8-41e1-928d-1bba8fb9f7d7
-
2399
865
25
20
-
2413
875
- 1
- Print, Reflect and Error streams
- c01c7c67-2ce9-42db-98c8-ac53917d2607
- out
- out
- false
- 0
-
2454
705
25
22
-
2466.5
716.25
- Output parameter Pts
- 03112bf2-28fb-457f-b3d5-277c7e00bc21
- Pts
- Pts
- false
- 0
-
2454
727
25
23
-
2466.5
738.75
- Output parameter Crv
- 49ed72a9-4d6b-4881-ac0f-b8700f17fd26
- Crv
- Crv
- false
- 0
-
2454
750
25
22
-
2466.5
761.25
- Output parameter L
- 88bfd5c3-b1ad-4215-961b-9ab638f2cfd6
- L
- L
- false
- 0
-
2454
772
25
23
-
2466.5
783.75
- Output parameter W
- 5419ee09-aef9-46c4-abed-2d8045ba1ca7
- W
- W
- false
- 0
-
2454
795
25
22
-
2466.5
806.25
- Output parameter H
- b01ed3c0-f6fa-4b63-bd7e-3eef2c0d55a4
- H
- H
- false
- 0
-
2454
817
25
23
-
2466.5
828.75
- Output parameter A
- 7adf1044-78f7-4bcc-874b-e500d7bbbd0d
- A
- A
- false
- 0
-
2454
840
25
22
-
2466.5
851.25
- Output parameter F
- 06232a84-6a80-4dfa-8393-98b404b97208
- F
- F
- false
- 0
-
2454
862
25
23
-
2466.5
873.75
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 2398bd00-b514-4723-b31f-c436e1ae908b
- Number Slider
- length
- false
- 0
-
1782
726
382
20
-
1782.348
726.8306
- 2
- 1
- 0
- 400
- 0
- 0
- 250
- 3581f42a-9592-4549-bd6b-1c0fc39d067b
- Construct Point
- Construct a point from {xyz} coordinates.
- cf3f354f-4379-4525-be10-5b0dbf31bcff
- Construct Point
- Pt
-
2254
641
67
64
-
2285
673
- {x} coordinate
- 661f67f9-9359-4ee5-a58c-df76414fabf0
- X coordinate
- X
- false
- c2ff491e-b898-432c-8e6a-7db46434934a
- 1
-
2256
643
14
20
-
2264.5
653
- 1
- 1
- {0}
- 0
- {y} coordinate
- fe9dc686-4183-43f9-863d-c8c499a24577
- Y coordinate
- Y
- false
- 0
-
2256
663
14
20
-
2264.5
673
- 1
- 1
- {0}
- 0
- {z} coordinate
- 878e78bd-0868-4cae-b9a9-ef4a62dac81e
- Z coordinate
- Z
- false
- 0
-
2256
683
14
20
-
2264.5
693
- 1
- 1
- {0}
- 0
- Point coordinate
- 75154365-a588-4c21-86a3-ce81e626861d
- Point
- Pt
- false
- 0
-
2300
643
19
60
-
2309.5
673
- d5967b9f-e8ee-436b-a8ad-29fdcecf32d5
- Curve
- Contains a collection of generic curves
- 934a131f-f506-4502-86d5-aca65a992e3c
- Curve
- Crv
- false
- 49ed72a9-4d6b-4881-ac0f-b8700f17fd26
- 1
-
2525
750
50
24
-
2550.661
762.5297
- 17b7152b-d30d-4d50-b9ef-c9fe25576fc2
- XY Plane
- World XY plane.
- true
- b2200c91-bbca-48a4-a165-a7f1e2fe3c5f
- XY Plane
- XY
-
2261
707
64
28
-
2292
721
- Origin of plane
- 8589cc40-e2f3-4654-885c-b57ca3fd526a
- Origin
- O
- false
- 0
-
2263
709
14
24
-
2271.5
721
- 1
- 1
- {0}
-
0
0
0
- World XY plane
- f3933593-ac71-4dcf-9de1-01828b79508a
- Plane
- P
- false
- 0
-
2307
709
16
24
-
2315
721
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- c2ff491e-b898-432c-8e6a-7db46434934a
- Panel
- false
- 0
- 0
- 0
-
2170
644
50
20
- 0
- 0
- 0
-
2170.805
644.7167
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
2131.598
592.215
-
2482.523
592.215
-
2482.523
607.2424
-
2131.598
607.2424
- A quick note
- Microsoft Sans Serif
- 61857d57-1c68-49a3-ad6f-54433ce11822
- false
- Scribble
- Scribble
- 16
- Connect the Range component to Wid (ooooh)
-
2126.598
587.215
360.9243
25.02734
-
2131.598
592.215
- 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe
- Scribble
- true
-
29.21105
1018.627
-
472.5363
1018.376
-
472.5443
1032.464
-
29.21903
1032.715
- A quick note
- Microsoft Sans Serif
- a735556e-8f05-4f8e-b6ab-1cc5ff398382
- false
- Scribble
- Scribble
- 15
- For Force calc, Young's modulus (material-dependent, in GPa)
-
24.21105
1013.376
453.3333
24.33868
-
29.21105
1018.627
- 59e0b89a-e487-49f8-bab8-b5bab16be14c
- Panel
- A panel for custom notes and text values
- 64b83d9b-5ae1-4022-b79e-c9135d3cdfc6
- Panel
- false
- 0
- 0
- 0
-
2102
767
50
20
- 0
- 0
- 0
-
2102.709
767.0847
-
255;255;250;90
- true
- true
- true
- false
- false
- true
- 57da07bd-ecab-415d-9d86-af36d7073abc
- Number Slider
- Numeric slider for single values
- 8162af0c-aab0-4024-a905-8206506ff4fd
- Number Slider
- height
- false
- 0
-
1344
308
384
20
-
1344.632
308.1685
- 2
- 1
- 0
- 200
- -200
- 0
- -56.13
-
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