How do you build a capsule solid in python script

what is the fastest way to build a generic capsule with give any orientation by a vector, given the following parameters

A length of cylindrical height
r radius of cylinder and hemispheres
x y z location of the center of the solid

alpha, beta, gamma as the vector determining the orientation of the capsule( ahpha^2+beta^2+gamma^2=1), say 1,0,0 meaning it is along x axis, but would like to extend it to any generic direction not just on x or y or z axis by giving the proper orientation vector.

import Rhino
import scriptcontext
import System.Guid

r=4
h=8
x = 5
y = 10
z = 4
alpha = 1 # Along x axis
beta  = 0
gamma = 0 



center = Rhino.Geometry.Point3d(x, y, z)
c = Rhino.Geometry.Circle(center, r)
# how to rotate the circle then move it to the ends of the cylinder so you could sweep to generate the cylinder surface
# then copy the center to the end of the cylinder top/bottom to generate the hemi-spheres and join 3 surfaces together? # I got stuck at the rotation part and am not quite familiar with the syntax...

Thank you for your help.

If you are going to orient multiples, I prefer to create the object flat relative to the World axis and then rotate/translate it into position. Below is a quick sample which creates a series of randomly oriented and spaced capsules in a cube. There are obviously different ways to construct the capsule, I prefer as a polysurface composed of the cylinder and two hemispheres rather than joining the revolve curves and getting one single surface.

The capsules are all the samesize in the example, it’s certainly also possible to create random-sized capsules with a couple more lines of code.

Edit- more fun version that adds random color to each capsule…

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino, random, System

def MakeCapsule(rad,ht,tol):
    #makes capsule oriented along X-axis, centered at 0
    #I prefer to create this as 3 separate surfaces and join
    #points
    ptA=Rhino.Geometry.Point3d(-ht,rad,0)
    ptB=Rhino.Geometry.Point3d(-(ht+rad),0,0)
    ptC=Rhino.Geometry.Point3d(ht,rad,0)
    ptD=Rhino.Geometry.Point3d(ht+rad,0,0)
    
    #curve geometry
    x_vec=Rhino.Geometry.Vector3d(1,0,0)
    line_crv=Rhino.Geometry.LineCurve(ptA,ptC)
    arc_R=Rhino.Geometry.Arc(ptA,-x_vec,ptB).ToNurbsCurve()
    arc_L=Rhino.Geometry.Arc(ptC,x_vec,ptD).ToNurbsCurve()
    
    #revolve surfaces
    axis=Rhino.Geometry.Line(ptB,ptD)
    srf_R=Rhino.Geometry.RevSurface.Create(arc_R,axis).ToBrep()
    srf_C=Rhino.Geometry.RevSurface.Create(line_crv,axis).ToBrep()
    srf_L=Rhino.Geometry.RevSurface.Create(arc_L,axis).ToBrep()
    
    #join
    brep=Rhino.Geometry.Brep.JoinBreps([srf_R,srf_C,srf_L],tol)
    return brep[0]
    
def Get3RandomValues(min,max):
    x=random.randrange(min,max)
    y=random.randrange(min,max)
    z=random.randrange(min,max)
    return x,y,z
    
def CreateOrientCapsules():
    #test will create n number of capsules at different locations
    tol=sc.doc.ModelAbsoluteTolerance
    radius=rs.GetReal("Capsule radius?",1,minimum=tol)
    if not radius: return
    height=rs.GetReal("Cylinder section height?",2,minimum=tol)
    if not height: return
    extents=rs.GetReal("Extents cube?",100,minimum=tol)
    if not extents: return
    count=rs.GetInteger("Number of capsules?",10,minimum=1)
    if not count: return
    
    vecs=[] ; pts=[] ; colors=[]
    x_vec=Rhino.Geometry.Vector3d(1,0,0)
    origin=Rhino.Geometry.Point3d(0,0,0)
    
    for i in range(count):
        x,y,z=Get3RandomValues(-extents/2,extents/2)
        pts.append(Rhino.Geometry.Point3d(x,y,z))
        x,y,z=Get3RandomValues(-extents/2,extents/2)
        vecs.append(Rhino.Geometry.Vector3d(x,y,z))
        r,g,b=Get3RandomValues(0,255)
        colors.append(System.Drawing.Color.FromArgb(r,g,b))
    
    sc.doc.Views.RedrawEnabled=False
    for i in range(count):
        cap=MakeCapsule(radius,height,tol)
        xform=Rhino.Geometry.Transform.Rotation(x_vec,vecs[i],origin)
        cap.Transform(xform)
        xform=Rhino.Geometry.Transform.Translation(pts[i]-origin)
        cap.Transform(xform)
        objID=sc.doc.Objects.AddBrep(cap)
        rs.ObjectColor(objID,colors[i])
CreateOrientCapsules()

–Mitch

1 Like

@ludicris, below is my shortest version:

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs
    
def Capsule(curve, radius):
    brep = Rhino.Geometry.Brep()
    mode = Rhino.Geometry.PipeCapMode.Round
    t1 = scriptcontext.doc.ModelAbsoluteTolerance
    t2 = scriptcontext.doc.ModelAngleToleranceRadians
    rc = brep.CreatePipe(curve, radius, False, mode, False, t1, t2)
    if rc: return rc[0]
    
def GetCapsulePoints():
    pts = rs.GetPoints(True, False, "first point", "second point", 2)
    if not pts: return
    if len(pts) == 1: return
    if pts[0] == pts[1]: return
    curve = Rhino.Geometry.Line(pts[0], pts[1]).ToNurbsCurve()
    capsule = Capsule(curve, radius=0.5*pts[0].DistanceTo(pts[1]))
    if capsule:
        scriptcontext.doc.Objects.AddBrep(capsule)
        scriptcontext.doc.Views.Redraw()
    
if __name__=="__main__":
    GetCapsulePoints()

You can just pass two points by creating a line from your points, then convert the line to a curve and pass it to the Capsule function.

c.

1 Like