描述:
想把之前沒搞懂packing 的邏輯在整理一下,並且翻出之前網路上david 寫好的vb legacy Circle packing component 來轉譯成 C#。起初想說只要把變數名稱還有方法宣告的部分改寫就好,沒想到果然在過程中還是遇到一些問題。像是再判斷創建點是否在現有的圓內時,需要跳出迴圈繼續計算下一個創建點直到創建點都在現有圓外時的部分。
vb 的寫法是
For Each crc As OnCircle In circles
If (point.DistanceTo(crc.Center) < crc.radius) Then Continue Do
Next
C#的寫法如果只用continue 則程式的判斷將不會去除圓內點
if(point.DistanceTo(crc.Center) < crc.Radius){
continue;
}
圓內點沒被排除狀況 |
C#正確改寫方法應該使用關鍵字 goto; 離開判斷並且到最外層的do while迴圈
if(point.DistanceTo(crc.Center) < crc.Radius){
goto label;
}
正確結果 |
參考案例 :
http://www.grasshopper3d.com/forum/topics/circle-packing-constraints?commentId=2985220%3AComment%3A105142
http://www.grasshopper3d.com/forum/topics/circle-packing-1
檔案 :
流程步驟 :
Main Code:
vb legacy parts ->
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
If (N <= 0) Then Return
If (Not C.IsClosed) Then
Print("Your input curve is not closed.")
Return
End If
Dim bbox As OnBoundingBox = C.BoundingBox()
Dim U As New OnInterval(bbox.Min().x, bbox.Max().x)
Dim V As New OnInterval(bbox.Min().y, bbox.Max().y)
Dim rnd As New Random(7)
Dim circles As New List(Of OnCircle)
Dim attempts As Int32 = 0
Do While (attempts < 1000)
attempts += 1
Dim point As New On3dPoint(U.ParameterAt(rnd.NextDouble()), V.ParameterAt(rnd.NextDouble()), 0)
If (Rhutil.RhinoPointInPlanarClosedCurve(point, C, OnPlane.World_xy) <> 1) Then Continue Do
For Each crc As OnCircle In circles
If (point.DistanceTo(crc.Center) < crc.radius) Then Continue Do
Next
Dim ct As Double : C.GetClosestPoint(point, ct)
Dim cp As On3dPoint = C.PointAt(ct)
Dim radius As Double = point.DistanceTo(cp)
For Each crc As OnCircle In circles
Dim dist As Double = point.DistanceTo(crc.Center) - crc.radius
If (dist < radius) Then radius = dist
Next
Dim circle As New OnCircle(point, radius)
circles.add(circle)
If (circles.Count >= N) Then Exit Do
attempts = 0
Loop
A = circles
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
C# parts ->
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bbox = xCrv.GetBoundingBox(true);
Interval U = new Interval(bbox.Min.X, bbox.Max.X);
Interval V = new Interval(bbox.Min.Y, bbox.Max.Y);
Random rnd = new Random(7);
List<Circle> circles = new List<Circle>();
int attempts = 0;
label: do{
attempts += 1;
Point3d point = new Point3d(U.ParameterAt(rnd.NextDouble()), V.ParameterAt(rnd.NextDouble()), 0);
//point inside existing circle -> regenerate a new point//
foreach(Circle crc in circles){
if(point.DistanceTo(crc.Center) < crc.Radius){
goto label;
}
}
//using bounding points as base point to calculate closest point//
Double ct;
xCrv.ClosestPoint(point, out ct);
Point3d cp = xCrv.PointAt(ct);
Double radius = point.DistanceTo(cp);;
//point outside existing circle -> find the closest distance//
foreach(Circle crc in circles){
Double dist = point.DistanceTo(crc.Center) - crc.Radius;
if(dist < radius){
radius = dist;
}
}
Circle circle = new Circle(point, radius);
circles.Add(circle);
if(circles.Count >= Num){
break;
}
}while(attempts < 1000);
Acrv = circles;
結果圖片:
基本circle packing |
顯示圓內點 |
把之前找尋最近點的function 導入,產生不同圖形 |
把之前找尋最近點的function 導入,並刪除交集線段,產生不同圖形 |
套用在不同曲線上 |
沒有留言:
張貼留言