Created
June 14, 2019 03:44
-
-
Save pgolay/b34fb43926dacef61a5b05276b9eb8b5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Rhino | |
import scriptcontext as sc | |
import rhinoscriptsyntax as rs | |
import math | |
class GO_FilterPrevious(Rhino.Input.Custom.GetObject): | |
#Make sure not to allow selection of previously | |
#dogboned curves in the same run of the script | |
def __init__(self, ids): | |
self.m_ids = ids | |
self.SubObjectSelect = False | |
def CustomGeometryFilter(self, rhino_object, geometry, component_index): | |
if not geometry.IsClosed: | |
return False | |
if not geometry.TryGetPlane()[0]: | |
return False | |
if rhino_object.Id in self.m_ids: | |
return False | |
return True | |
def DogBone(): | |
pi = math.pi | |
#make a .001" offset | |
inch = Rhino.UnitSystem.Inches | |
units = sc.doc.ModelUnitSystem | |
offset = .001*Rhino.RhinoMath.UnitScale(inch, units) | |
#Get radius, side (hole/outer) and depth factor defsults | |
rad = 1 | |
if sc.sticky.has_key("DOGBONE_RAD"): | |
rad = sc.sticky["DOGBONE_RAD"] | |
outer=False | |
if sc.sticky.has_key('DOGBONE_SIDE'): | |
outer = sc.sticky['DOGBONE_SIDE'] | |
factor = .05 | |
if sc.sticky.has_key('DOGBONE_FACTOR'): | |
factor = sc.sticky['DOGBONE_FACTOR'] | |
tol = sc.doc.ModelAbsoluteTolerance | |
aTol = sc.doc.ModelAngleToleranceRadians | |
#keep a list of ids that have already been dogboned | |
ids = [] | |
#loop to allow any number of curves to be dogboned | |
while True: | |
#Loop to allow settings changes per curve | |
while True: | |
go = Rhino.Input.Custom.GetObject() | |
go = GO_FilterPrevious(ids) | |
#go.GeometryAttributeFilter=Rhino.Input.Custom.GeometryAttributeFilter.Sub | |
go.GeometryFilter = Rhino.DocObjects.ObjectType.Curve | |
go.DisablePreSelect() | |
go.SubObjectSelect = False | |
oprad = Rhino.Input.Custom.OptionDouble(rad,True, tol*10) | |
go.AddOptionDouble("CutterRadius", oprad) | |
opSide = Rhino.Input.Custom.OptionToggle(outer, "Yes", "No") | |
go.AddOptionToggle("Hole", opSide) | |
opFactor = Rhino.Input.Custom.OptionDouble(factor,0, 1 ) | |
go.AddOptionDouble("DepthFactor", opFactor) | |
go.AcceptNumber(True, False) | |
#go.SetCustomGeometryFilter(is_new_id) | |
ret = go.Get() | |
if( go.CommandResult() != Rhino.Commands.Result.Success ): | |
return | |
if ret == Rhino.Input.GetResult.Option: | |
rad = oprad.CurrentValue | |
sc.sticky["DOGBONE_RAD"] = rad | |
outer = opSide.CurrentValue | |
sc.sticky['DOGBONE_SIDE'] = outer | |
factor = opFactor.CurrentValue | |
sc.sticky['DOGBONE_FACTOR'] = factor | |
continue | |
if ret == Rhino.Input.GetResult.Number: | |
rad = go.Number() | |
sc.sticky["DOGBONE_RAD"] = rad | |
continue | |
if ret == Rhino.Input.GetResult.Object: | |
objRef = go.Object(0) | |
point = objRef.SelectionPoint() | |
crv, par = objRef.CurveParameter() | |
obj = go.Object(0).Object() | |
Id = objRef.ObjectId | |
break | |
simOp = Rhino.Geometry.CurveSimplifyOptions.All | |
simpleCrv = crv.Simplify(Rhino.Geometry.CurveSimplifyOptions.All, tol, aTol) | |
if simpleCrv is not None:crv = simpleCrv | |
# the kink discontinuity | |
discoType= Rhino.Geometry.Continuity.G1_locus_continuous | |
disc = [crv.PointAtStart] | |
crv = crv.ToNurbsCurve() | |
dom = crv.Domain | |
t0 = dom.Min | |
t1 = dom.Max | |
#a list of kink parameters | |
discpar = [] | |
get_next = True | |
planeRC, crvPlane = crv.TryGetPlane() | |
arcInt = Rhino.Geometry.Interval(pi/2, (3*pi)/2) | |
boolCrvs = [] | |
#boolCrvs.append(crv) | |
#Set containment of the test point according to | |
#whether the cut is a hole or outer | |
pContainment = Rhino.Geometry.PointContainment.Outside | |
if outer: | |
pContainment = Rhino.Geometry.PointContainment.Inside | |
while get_next == True: | |
get_next, t = crv.GetNextDiscontinuity(discoType, t0, t1) | |
if get_next: | |
pt = crv.PointAt(t) | |
disc.append(crv.PointAt(t)) | |
discpar.append(t) | |
t0 = t | |
circ = Rhino.Geometry.Circle(pt, rad+offset).ToNurbsCurve() | |
#Iteresect the circle with the input curve | |
iInfo = Rhino.Geometry.Intersect.Intersection.CurveCurve(crv,circ, tol, tol) | |
#Set the test point between the two intersection points. | |
testPt = ( iInfo[0].PointA + iInfo[1].PointA)/2 | |
#Make a direction vector bisecting the kink | |
vecX = testPt-pt | |
vecX.Unitize() | |
#check if the test point is inside or outside the curve and skip | |
#or not, accordingly. | |
if crv.Contains(testPt) == pContainment: | |
continue | |
#set a plane at the point using the direction vector | |
vecY = Rhino.Geometry.Vector3d(vecX) | |
vecY.Rotate(pi/2, crvPlane.ZAxis) | |
plane = Rhino.Geometry.Plane(pt, vecX, vecY) | |
#move the plane inward in the corner to avoid too much cut. | |
#User sets the amount | |
plane.Origin = pt + vecX*(1-factor)*rad | |
#make a new circle at the plane origin such that the seam is on the direction vector | |
circle = Rhino.Geometry.Circle(plane, rad+offset) | |
#find the quads where the tangent is parallel to the direction vector | |
quad1 = circle.PointAt(pi/2) | |
quad2 = circle.PointAt((3*pi)/2) | |
#make lines from the quads in vector direction | |
line1 = Rhino.Geometry.Line(quad1,quad1+vecX) | |
line2 = Rhino.Geometry.Line(quad2,quad2+vecX) | |
# extend the lines to the curve. | |
info1 = Rhino.Geometry.Intersect.Intersection.CurveLine(crv, line1, tol, tol) | |
iPts = [item.PointA for item in info1] | |
iP1 = iPts[rs.PointArrayClosestPoint(iPts, quad1)] | |
info2 = Rhino.Geometry.Intersect.Intersection.CurveLine(crv, line2, tol, tol) | |
iPts = [item.PointA for item in info2] | |
iP2 = iPts[rs.PointArrayClosestPoint(iPts, quad2)] | |
#make new curves bounding the region to be cut and add them to a list | |
lines = [] | |
lines.append(Rhino.Geometry.LineCurve(Rhino.Geometry.Line(quad1, iP1))) | |
lines.append(Rhino.Geometry.LineCurve(Rhino.Geometry.Line(quad2, iP2))) | |
lines.append(Rhino.Geometry.LineCurve(Rhino.Geometry.Line(iP1, iP2))) | |
lines.append(Rhino.Geometry.ArcCurve(Rhino.Geometry.Arc(circle,arcInt))) | |
x = Rhino.Geometry.Curve.JoinCurves(lines) | |
if len(Rhino.Geometry.Intersect.Intersection.CurveSelf(x[0], tol)) == 0 : | |
boolCrvs.append(x[0]) | |
else: | |
break | |
pass | |
#BooleanUnion or Difference the curve regions with the input curve. | |
if not outer: | |
res = Rhino.Geometry.Curve.CreateBooleanUnion(boolCrvs + [crv]) | |
else: | |
res = Rhino.Geometry.Curve.CreateBooleanDifference( crv, boolCrvs) | |
if len(res) > 0: | |
db = res[0] | |
#make sure the curve was actually changed before replacing it. | |
if db.GetLength() != crv.GetLength: | |
db = db.Simplify(Rhino.Geometry.CurveSimplifyOptions.All, tol, aTol) | |
sc.doc.Objects.Replace(Id, db ) | |
ids.append(Id) | |
sc.doc.Views.Redraw() | |
if __name__ == "__main__": | |
DogBone() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment