Skip to content

Instantly share code, notes, and snippets.

@pgolay
Last active December 30, 2019 00:17
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save pgolay/0c737cdd7c462ddd798622f72ca6298b to your computer and use it in GitHub Desktop.
import rhinoscriptsyntax as rs
import Rhino
import scriptcontext as sc
import math
import System.Collections.Generic.IEnumerable as IEnumerable
import System.Double as sd
def FilletSrfCorner():
tol = sc.doc.ModelAbsoluteTolerance
pi = math.pi
def RebuildArc(arc):
deg = arc.AngleDegrees
if deg <=45:
rebuild = [3,4]
elif 70 >= deg > 45:
rebuild = [4,5]
elif 90 >= deg > 70:
rebuild = [5,6]
else:
rebuild = [5, int(deg/15)]
return arc.Rebuild(rebuild[1], rebuild[0], True)
planes = [None, rs.ViewCPlane(), Rhino.Geometry.Plane.WorldXY]
def GetInputs(count):
planeList = ['Auto','CPlane','WorldXY']
while True:
#defaults
rad = 1
if sc.sticky.has_key('NP_RAD'):
rad = sc.sticky['NP_RAD']
planeIdx = 0
if sc.sticky.has_key('FT_PLANE_IDX'):
planeIdx = sc.sticky['FT_PLANE_IDX']
else:
sc.sticky['FT_PLANE_IDX'] = planeIdx
go = Rhino.Input.Custom.GetObject()
promptString = "Select an edge near the corner to fillet"
go.SetCommandPrompt(promptString)
#options
opRad = Rhino.Input.Custom.OptionDouble(rad)
go.AddOptionDouble("Radius", opRad)
go.AddOptionList("Plane", planeList, planeIdx)
if count > 0:
go.AddOption("Undo")
go.AcceptNumber(True, False)
go.GeometryFilter = Rhino.DocObjects.ObjectType.EdgeFilter
go.EnablePreSelect(False, True)
rc = go.Get()
if go.CommandResult()!=Rhino.Commands.Result.Success:
return go.CommandResult()
if rc==Rhino.Input.GetResult.Object:
objRef=go.Object(0)
return objRef, rad
elif rc==Rhino.Input.GetResult.Number:
rad = go.Number()
sc.sticky['NP_RAD']= rad
continue
elif rc==Rhino.Input.GetResult.Option:
idx = go.OptionIndex()
if idx == 1:
rad = opRad.CurrentValue
sc.sticky['NP_RAD']= rad
elif idx == 2:
planeIdx = go.Option().CurrentListOptionIndex
sc.sticky['FT_PLANE_IDX'] = planeIdx
else:
sc.doc.Objects.Replace(srfId,brep)
count = 0
sc.doc.Views.Redraw()
continue
count = 0
while True:
#brep = rs.coercebrep(srfId)
inputs = GetInputs(count)
if inputs == Rhino.Commands.Result.Cancel: return
count += 1
objRef, rad = inputs
srfId = objRef.ObjectId
brep = objRef.Brep()
verts = brep.Vertices
vLocs = [vert.Location for vert in verts]
par1 = objRef.CurveParameter()[1]
selPt = objRef.SelectionPoint()
idx = rs.PointArrayClosestPoint(vLocs,selPt)
vert = verts[idx]
pt = vert.Location
crvs = [brep.Edges[vert.EdgeIndices()[n]].EdgeCurve for n in range(vert.EdgeIndices().Count)]
pass
#sub1, sub2, pts = SortCurveEnds(edges)
crv1 =crvs[0]
crv2 = crvs[1]
o = vert.Location
par1 = crv1.ClosestPoint(o)[1]
par2 = crv2.ClosestPoint(o)[1]
crvTan1 = crv1.TangentAt(par1)
crvTan2 = crv2.TangentAt(par2)
planeIdx = sc.sticky['FT_PLANE_IDX']
if planeIdx ==0:
myPlane = Rhino.Geometry.Plane(o, crvTan1, crvTan2)
else:
myPlane = planes[planeIdx]
pull1 = Rhino.Geometry.Curve.ProjectToPlane(crv1,myPlane)
pull2 = Rhino.Geometry.Curve.ProjectToPlane(crv2,myPlane)
ft = Rhino.Geometry.Curve.CreateFillet(pull1, pull2, rad, par1, par2)
if not ft: return
if brep.Faces[0].IsPlanar():
crv = Rhino.Geometry.ArcCurve(ft)
else:
crv = RebuildArc(Rhino.Geometry.ArcCurve(ft))
cPts = crv.Points
# get plane normal lines from the ends of the fillets and
# intersect with the input curves to find where to place the
# rebuilt fillet ends and tangent directions
bb = crv1.GetBoundingBox(False)
bb.Union(crv2.GetBoundingBox(False))
norm = Rhino.Geometry.Line(crv.PointAtStart,crv.PointAtStart + myPlane.ZAxis)
norm.ExtendThroughBox(bb)
if norm.Length == 0:
tanPt1 = crv.PointAtStart
else:
norm = Rhino.Geometry.LineCurve(norm)
intPt = Rhino.Geometry.Intersect.Intersection.CurveCurve(crv1, norm, tol, tol)
tanPt1 = intPt[0].PointA
tanPar1 = crv1.ClosestPoint(tanPt1)[1]
tan1 = crv1.TangentAt(tanPar1)
norm = Rhino.Geometry.Line(crv.PointAtEnd,crv.PointAtEnd + myPlane.ZAxis)
norm.ExtendThroughBox(bb)
if norm.Length == 0:
tanPt2 = crv.PointAtEnd
else:
norm = Rhino.Geometry.LineCurve(norm)
intPt = Rhino.Geometry.Intersect.Intersection.CurveCurve(crv2, norm, tol, tol)
tanPt2 = intPt[0].PointA
tanPar2 = crv2.ClosestPoint(tanPt2)[1]
tan2 = crv2.TangentAt(tanPar2)
# decide which way the tangents should go.
tanStart = cPts[1].Location-cPts[0].Location
tanEnd = cPts[cPts.Count-2].Location - cPts[cPts.Count-1].Location
if Rhino.Geometry.Vector3d.VectorAngle(tanStart,tan1) > pi/2:
tan1.Reverse()
if Rhino.Geometry.Vector3d.VectorAngle(tanEnd,tan2) > pi/2:
tan2.Reverse()
rc, cp1 = crv1.ClosestPoint(crv.PointAtStart)
rc, cp2 = crv2.ClosestPoint(crv.PointAtEnd)
d1 = cPts[0].Location.DistanceTo(cPts[1].Location)
d2 = cPts[cPts.Count-1].Location.DistanceTo(cPts[cPts.Count-2].Location)
tan1 = tan1*d1
tan2 = tan2*d2
cPts.SetPoint(0, crv1.PointAt(cp1))
cPts.SetPoint(1, crv1.PointAt(cp1) + tan1)
cPts.SetPoint(cPts.Count-1, crv2.PointAt(cp2))
cPts.SetPoint(cPts.Count-2, crv2.PointAt(cp2)+ tan2)
if cPts.Count > 4:
#move the plane to the second cp location:
myPlane.Origin = cPts[cPts.Count-2].Location
#find the direction vector and unitize it
vecDir = myPlane.ClosestPoint(cPts[1].Location) - cPts[1].Location
#vecDir.Unitize()
vecDir.Reverse()
#get curve point locations in plane coorinates
xform = Rhino.Geometry.Transform.PlaneToPlane( myPlane,Rhino.Geometry.Plane.WorldXY )
locs = [xform*cPt.Location for cPt in cPts]
#get the locations as projected to the plane
planePts = [myPlane.ClosestPoint(cPt.Location) for cPt in cPts]
#get the fillet curve params for the tangent points
crvDom = crv.Domain
ftPar1 = crv.ClosestPoint(cPts[1].Location)[1]
ftPar2 = crv.ClosestPoint(cPts[cPts.Count-2].Location)[1]
#make a domain between the tangent points
domPts = Rhino.Geometry.Interval(ftPar1, ftPar2)
for i in range(2,cPts.Count-2):
ptPar = crv.ClosestPoint(cPts[i].Location)[1]
# ptPar = ptPar - crvDom.Min #<<< par in domPts
# get the normalized param of the point in
# the sub-domain
nPar = domPts.NormalizedParameterAt(ptPar)
z = (math.cos(nPar * pi)+1)/2
targ = planePts[i]+vecDir*z
cPts.SetPoint(i, targ)
splitter = crv.PullToBrepFace(brep.Faces[0], tol)[0]
breps = brep.Split.Overloads[IEnumerable[Rhino.Geometry.Curve], sd]( [splitter], tol)
if breps:
for item in breps:
test = item.Faces[0].PullPointsToFace([pt], tol)
if len(test) == 0:
sc.doc.Objects.Replace(objRef.ObjectId,item)
sc.doc.Views.Redraw()
break
if __name__== '__main__': FilletSrfCorner()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment