Forgot password?

Create an account!

Forum

« back

RhinoScript – Circles packed on edges overlap

Messages

Please log in to write a message.

  • 5. speden2 (Mar 19, 2009 03.11):

    Thanks Hanno - I ended up figuring this out last night. I've posted the new code below. Seems I still have quite a bit to learn. Now that I've got this to work, my next challenge is to pack the edges of a surface with non-linear edges (which the code below does not work for, as I've using vectors between the vertex points). But I have an idea a to how to approach it, which is to create edge curves from the surface, and use the curvearclength to generate new points and use vectors between points to test radii distances. We'll see how this works out.

    Option Explicit
    'Script written by <insert name>
    'Script copyrighted by <insert company name>
    'Script version Saturday, March 14, 2009 1:24:27 PM
    Randomize

    Dim RandomClass1
    Set RandomClass1 = CreateObject("System.Random")

    Call Main()
    Sub Main()

            Dim srfBoundingPlane
            Dim minRadius, maxRadius
            Dim arrGlobalNSET
           
           
           
            srfBoundingPlane = Rhino.GetObject("Select bounding plane for Sphere packing", 8)
            'minRadius = Rhino.GetInteger("Enter the min radius")
            'maxRadius = Rhino.GetInteger("Enter the max radius")
           
            minRadius = .5
            maxRadius = 1
           
            Call PackEdges(srfBoundingPlane, maxRadius, minRadius,arrGlobalNSET)
    End Sub

    Function PackEdges(srfBoundingPlane, maxRadius, minRadius, arrGlobalNSET)

            Dim i, j, radius, circleCenter, arrCircles(100), totalDiameter, distanceToVertexCircle, remainingDistance
            Dim CircleNormal, CirclePlane, srfFrame, circle
            Dim arrDomU, arrDomV
            Dim arrVerticesCircles(4)

            arrDomU = Rhino.SurfaceDomain(srfBoundingPlane, 0)
            arrDomV = Rhino.SurfaceDomain(srfBoundingPlane, 1)
           
            ' Add circles at vertices
            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
            circleCenter = Array(arrDomU(0),arrDomV(0))
            arrVerticesCircles(0) = CreateCircle(srfBoundingPlane, circleCenter, radius)
            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
            circleCenter = Array(arrDomU(1),arrDomV(0))
            arrVerticesCircles(1) = CreateCircle(srfBoundingPlane, circleCenter, radius)
            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
            circleCenter = Array(arrDomU(1),arrDomV(1))
            arrVerticesCircles(2) = CreateCircle(srfBoundingPlane, circleCenter, radius)
            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
            circleCenter = Array(arrDomU(0),arrDomV(1))
            arrVerticesCircles(3) = CreateCircle(srfBoundingPlane, circleCenter, radius)

            Call PackEdge(srfBoundingPlane, minRadius, maxRadius, arrCircles, arrVerticesCircles(0), arrVerticesCircles(1))
            Call PackEdge(srfBoundingPlane, minRadius, maxRadius, arrCircles, arrVerticesCircles(1), arrVerticesCircles(2))
            Call PackEdge(srfBoundingPlane, minRadius, maxRadius, arrCircles, arrVerticesCircles(0), arrVerticesCircles(3))
            Call PackEdge(srfBoundingPlane, minRadius, maxRadius, arrCircles, arrVerticesCircles(3), arrVerticesCircles(2))
           
           
    End Function

    Sub PackEdge(srfBoundingPlane, minRadius, maxRadius, ByRef arrCircles, startCircle, endCircle)
           
            Dim i : i = 0
            Dim circleCenter, lastRadius, endRadius, distanceToVertexCircle, newRadius, circle, remainingDistance
            Dim vectorToCircleCtr, vectorToVertexCircle, vectorLength, vectorScale
            Dim newCtr, upperPt
           
            newRadius = Rhino.CircleRadius(startCircle)
            endRadius = Rhino.CircleRadius(endCircle)
            upperPt = Rhino.CircleCenterPoint(endCircle)
            newCtr = Rhino.CircleCenterPoint(startCircle)
            vectorToVertexCircle = Rhino.VectorCreate(upperPt, newCtr)
            vectorLength = Rhino.VectorLength(vectorToVertexCircle)
           
            Do
                    lastRadius = newRadius
                    Do
                            newRadius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
                            remainingDistance = (vectorLength - endRadius - (newRadius * 2) - lastRadius) / 2
                    Loop While minRadius > remainingDistance
                   
                    vectorScale = (lastRadius + newRadius) / Rhino.VectorLength(vectorToVertexCircle)
                    vectorToCircleCtr = Rhino.VectorScale(vectorToVertexCircle, vectorScale)
                    newCtr = Rhino.PointAdd(newCtr, vectorToCircleCtr)
                    circleCenter = Rhino.BrepClosestPoint(srfBoundingPlane,newCtr)(1)
                    circle = CreateCircle(srfBoundingPlane, circleCenter, newRadius)

                    vectorToVertexCircle = Rhino.VectorCreate(upperPt, newCtr)
                    vectorLength = Rhino.VectorLength(vectorToVertexCircle)
                   
                    distanceToVertexCircle = vectorLength - endRadius - newRadius
                   
                    Call Rhino.Print("lastRadius: " & lastRadius & ", newRadius: " & newradius & ", vectorScale: " & vectorScale & ", vectorLength: " _
                    & vectorLength & ", distanceToVertexCircle: " & distanceToVertexCircle)
                    If distanceToVertexCircle <= (maxRadius * 2) Then
                            lastRadius = newRadius
                            newRadius = distanceToVertexCircle / 2
                            vectorScale = (lastRadius + newRadius) / Rhino.VectorLength(vectorToVertexCircle)
                            vectorToCircleCtr = Rhino.VectorScale(vectorToVertexCircle, vectorScale)
                            newCtr = Rhino.PointAdd(newCtr, vectorToCircleCtr)
                            circleCenter = Rhino.BrepClosestPoint(srfBoundingPlane,newCtr)(1)
                            circle = CreateCircle(srfBoundingPlane, circleCenter, newRadius)
                            Exit Do
                    End If
            Loop
           
    End Sub

    Function CreateCircle(srfBoundingPlane, circleCenter, radius)
            Dim CirclePlane
           
            CirclePlane = Rhino.SurfaceFrame(srfBoundingPlane, circleCenter)
            CreateCircle = Rhino.AddCircle(CirclePlane, radius)

    End Function
  • 4. Hanno (Mar 18, 2009 11.02):

    Ok, I took a look at your code, and you are really mixing up u/v parameters and absolute positions. So your code only works if you have a rectangular plane (because the default parameterization matches the absolute lengths of the surface). But this is a special case - the surface domain can have arbitrary bounds and in most cases does not match the absolute lengths, so you need to take a look at methods that give you absolute coordinates from parameters like evaluateSurface().

  • 3. speden2 (Mar 16, 2009 18.46):

    Oh, sorry, I should have probably indicated what surface I am testing with. I'm not at home, so I can't get the exact dimensions, but it is basically an irregular quadrilateral (trapezium) - no sides parallel. My ultimate goal for this phase of the problem is to cover the edges of any surface with circles.

  • 2. Hanno (Mar 16, 2009 13.13):

    When I run this thing, nothing overlaps...

  • 1. speden2 (Mar 16, 2009 03.59):

    Hi

    I am working on a sphere packing problem with variable radii, although right now I'm trying to just pack a 2D plane. To do this, first the edges are packed with circles. This all seems to work, except on two of the edges the circles slightly overlap, and I cannot figure out why. Any insight would be appreciated.

    Option Explicit
    'Script written by <insert name>
    'Script copyrighted by <insert company name>
    'Script version Saturday, March 14, 2009 1:24:27 PM
    Randomize

    Dim RandomClass1
    Set RandomClass1 = CreateObject("System.Random")

    Call Main()
    Sub Main()

            Dim srfBoundingPlane
            Dim minRadius, maxRadius
            Dim arrGlobalNSET
           
           
           
            srfBoundingPlane = Rhino.GetObject("Select bounding plane for Sphere packing", 8)
            'minRadius = Rhino.GetInteger("Enter the min radius")
            'maxRadius = Rhino.GetInteger("Enter the max radius")
           
            minRadius = .5
            maxRadius = 1
           
            Call PackEdges(srfBoundingPlane, maxRadius, minRadius,arrGlobalNSET)
    End Sub

    Function PackEdges(srfBoundingPlane, maxRadius, minRadius, arrGlobalNSET)

            Dim i, j, radius, circleCenter, arrCircles(100), totalDiameter, distanceToVertexCircle, remainingDistance
            Dim CircleNormal, CirclePlane, srfFrame, circle
            Dim arrDomU, arrDomV
            Dim arrVerticesCircles(4)

            arrDomU = Rhino.SurfaceDomain(srfBoundingPlane, 0)
            arrDomV = Rhino.SurfaceDomain(srfBoundingPlane, 1)
           
            ' Add circles at vertices
            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
            circleCenter = Array(arrDomU(0),arrDomV(0))
            Call Rhino.AddPoint(Rhino.EvaluateSurface(srfBoundingPlane,circleCenter))
            arrVerticesCircles(0) = CreateCircle(srfBoundingPlane, circleCenter, radius)
            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
            circleCenter = Array(arrDomU(1),arrDomV(0))
            Call Rhino.AddPoint(Rhino.EvaluateSurface(srfBoundingPlane,circleCenter))
            arrVerticesCircles(1) = CreateCircle(srfBoundingPlane, circleCenter, radius)
            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
            circleCenter = Array(arrDomU(1),arrDomV(1))
            Call Rhino.AddPoint(Rhino.EvaluateSurface(srfBoundingPlane,circleCenter))
            arrVerticesCircles(2) = CreateCircle(srfBoundingPlane, circleCenter, radius)
            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
            circleCenter = Array(arrDomU(0),arrDomV(1))
            Call Rhino.AddPoint(Rhino.EvaluateSurface(srfBoundingPlane,circleCenter))
            arrVerticesCircles(3) = CreateCircle(srfBoundingPlane, circleCenter, radius)

            'Call PackEdge(srfBoundingPlane, minRadius, maxRadius, arrCircles, upperU, arrDomV(0), arrVerticesCircles(0), arrVerticesCircles(1), "U")
            Call PackEdge(srfBoundingPlane, minRadius, maxRadius, arrCircles, arrDomV(1), arrDomU(1), arrVerticesCircles(1), arrVerticesCircles(2), "V")
            'Call PackEdge(srfBoundingPlane, minRadius, maxRadius, arrCircles, upperV, arrDomU(0), arrVerticesCircles(0), arrVerticesCircles(3), "V")
            'Call PackEdge(srfBoundingPlane, minRadius, maxRadius, arrCircles, upperU, upperV, arrVerticesCircles(3), arrVerticesCircles(2), "U")
           
           
    End Function

    Sub PackEdge(srfBoundingPlane, minRadius, maxRadius, ByRef arrCircles, upperBound, controlBound, startCircle, endCircle, direction)
           
            Dim i : i = 0
            Dim circleCenter, totalDiameter, distanceToVertexCircle, remainingDistance, radius, circle
            Dim newCtr
           
            totalDiameter = Rhino.CircleRadius(startCircle)
            Call Rhino.Print("")
            Call Rhino.Print("totalDiameter: " & totalDiameter)
           
            Do
                   
                    distanceToVertexCircle = upperBound - Rhino.CircleRadius(endCircle) - totalDiameter
                    Do
                            radius  = RandomClass1.NextDouble() * (maxRadius - minRadius) + minRadius
                            remainingDistance = (distanceToVertexCircle - (radius * 2)) / 2
                            Call Rhino.Print("remainingDistance: " & remainingDistance)
                    Loop While minRadius > remainingDistance
                   
                    newCtr = totalDiameter + radius
                    Call Rhino.Print("newCtr: " & newCtr & ", radius: " & radius)
                    circleCenter = CreateCircleCenter(newCtr, controlBound, direction)
                    circle = CreateCircle(srfBoundingPlane, circleCenter, radius)
                    totalDiameter = totalDiameter + (radius * 2)
                    i = i+1
                    distanceToVertexCircle = upperBound - Rhino.CircleRadius(endCircle) - totalDiameter
                    Call Rhino.Print("Circle created: " & circle)
                    Call Rhino.Print("distanceToVertexCircle: " & distanceToVertexCircle)
                    If distanceToVertexCircle <= (maxRadius * 2) Then
                            radius = distanceToVertexCircle / 2
                            newCtr = totalDiameter + radius
                            circleCenter = CreateCircleCenter(newCtr, controlBound, direction)
                            circle = CreateCircle(srfBoundingPlane, circleCenter, radius)
                            Exit Do
                    End If
            Loop
           
    End Sub

    Function CreateCircle(srfBoundingPlane, circleCenter, radius)
            Dim CirclePlane
           
            CirclePlane = Rhino.SurfaceFrame(srfBoundingPlane, circleCenter)
            CreateCircle = Rhino.AddCircle(CirclePlane, radius)

    End Function

    Function CreateCircleCenter(X, Y, direction)

            If direction = "U" Then
                    CreateCircleCenter = Array(X, Y)
            Else
                    CreateCircleCenter = Array(Y, X)
            End If
    End Function

    Thanks,

    Sean

Recommend

Why are these buttons gray?