こちらの12年も前の記事なのですが、楽しそうなので
CATIAで行ってみました。
再帰プログラムによるフラクタル図形の描画:CodeZine(コードジン)
Option Explicit
Private Const LEVEL = 3
Dim mPnts As Object
Dim mDoc As PartDocument
Dim mPt As Part
Dim mFact As HybridShapeFactory
Dim m1_3 As Double
Dim m1_Sq3 As Double
Dim mPI_6 As Double
Sub CATMain()
If Not CanExecute("PartDocument") Then Exit Sub
m1_3 = 1 / 3
m1_Sq3 = 1 / Sqr(3)
mPI_6 = Atn(1) * 4 / 6
Set mDoc = CATIA.ActiveDocument
Set mPt = mDoc.Part
Set mFact = mPt.HybridShapeFactory
Dim p1, p2, p3
p1 = Array(100#, 160#)
p2 = Array(400#, 160#)
p3 = Array(250#, 420#)
Set mPnts = KCL.InitLst()
mPnts.Add p1
Call Get_KochCurvePos(p1, p2, LEVEL)
Call Get_KochCurvePos(p2, p3, LEVEL)
Call Get_KochCurvePos(p3, p1, LEVEL)
Dim Refs As Object
Set Refs = Get_PointRefs(mPnts)
Dim Poly As HybridShapePolyline
Set Poly = Init_Poly(Refs)
Dim Hbdy As HybridBody
Set Hbdy = mPt.hybridBodies.Add()
Hbdy.Name = "Koch_Curve"
Hbdy.AppendHybridShape Poly
mFact.DeleteObjectForDatum Refs(Refs.Count - 1)
MsgBox "Done"
End Sub
Private Function Init_Poly(ByVal Refs As Object) As HybridShapePolyline
Dim Poly As HybridShapePolyline
Set Poly = mFact.AddNewPolyline()
Dim i As Long
For i = 0 To Refs.Count - 2
Poly.InsertElement Refs(i), i
Next
Poly.Closure = True
mPt.UpdateObject Poly
Set Init_Poly = Poly
End Function
Private Function Get_PointRefs(ByVal Lst As Object) As Object
Dim Refs As Object
Set Refs = KCL.InitLst
Dim p As Variant
For Each p In mPnts
Refs.Add Init_PointRef(p)
Next
Set Get_PointRefs = Refs
End Function
Private Function Init_PointRef(ByVal Ary As Variant) As Reference
Dim p As HybridShapePointCoord
Set p = mFact.AddNewPointCoord(Ary(0), Ary(1), 0#)
mPt.UpdateObject p
Set Init_PointRef = mPt.CreateReferenceFromObject(p)
End Function
Private Sub Get_KochCurvePos(ByVal p1 As Variant, ByVal p2 As Variant, lv As Long)
Dim p3 As Variant, p4 As Variant, p5 As Variant
p3 = Array((2 * p1(0) + p2(0)) * m1_3, (2 * p1(1) + p2(1)) * m1_3)
p4 = Array((p1(0) + 2 * p2(0)) * m1_3, (p1(1) + 2 * p2(1)) * m1_3)
Dim xx As Double, yy As Double
xx = p2(0) - p1(0)
yy = -(p2(1) - p1(1))
Dim dist As Double
dist = Sqr(xx * xx + yy * yy) * m1_Sq3
Dim ang As Double
If xx >= 0 Then
ang = Atn(yy / xx) + mPI_6
p5 = Array(p1(0) + (dist * Cos(ang)), p1(1) - (dist * Sin(ang)))
Else
ang = Atn(yy / xx) - mPI_6
p5 = Array(p2(0) + (dist * Cos(ang)), p2(1) - (dist * Sin(ang)))
End If
If lv < 1 Then
mPnts.Add p3
mPnts.Add p5
mPnts.Add p4
mPnts.Add p2
Else
Call Get_KochCurvePos(p1, p3, lv - 1)
Call Get_KochCurvePos(p3, p5, lv - 1)
Call Get_KochCurvePos(p5, p4, lv - 1)
Call Get_KochCurvePos(p4, p2, lv - 1)
End If
End Sub
再帰でやるのもどうかな? とも思ったのですが、再帰の為の記事だったので
再帰のままです。
元の記事では、座標値を計算しながら線を描いてますが、
まとめて座標値を取得し、一本一本描かずに折れ線化しています。
(他にも計算コストの高そうな部分は、予めメンバ変数化し計算量を減らしてます)
円を指定して内接するようにしようかとも思いましたが、
利用価値が低そうなので、単にXY平面に描くだけにしました。
見ていたら雪の結晶を思い出し、よけいに寒くなりました・・・。