Skip to content

Instantly share code, notes, and snippets.

@pgolay
Last active July 21, 2018 03:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pgolay/eda7e0476b08c93a952c16c21be191ed to your computer and use it in GitHub Desktop.
Save pgolay/eda7e0476b08c93a952c16c21be191ed to your computer and use it in GitHub Desktop.
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
import System.Guid
import math
"""
Get the edge
if there are not two adjacent faces, ask for any other faces to mark.
Flip the curve as needed
Present the Divide options:
CurrentNumber int
Mode (Length/Number) bool
DivLength dbl
DivNum int
Marker size dbl
Add numbers bool
"""
def SeamMarkerDivide():
lFonts = [item.lower() for item in sorted(list(set(Rhino.DocObjects.Font.AvailableFontFaceNames())))]
fonts = [item.title() for item in lFonts] #to use in a list box if needed
for item in fonts:
if Rhino.DocObjects.Font(item).IsSingleStrokeFont:
fonts.insert(0, fonts.pop(fonts.index(item)))
sc.doc.Objects.UnselectAll()
sc.doc.Views.Redraw()
pi = math.pi
num =0
if sc.sticky.has_key("SEW_NUMBER"):
num = sc.sticky["SEW_NUMBER"]
rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select an edge to mark near the starting end.", False, Rhino.DocObjects.ObjectType.EdgeFilter)
if not objref or rc!=Rhino.Commands.Result.Success: return
pPt = objref.SelectionPoint()
obj = objref.Object()
brepId = obj.Id
if isinstance(obj.Geometry, Rhino.Geometry.Extrusion):
brep = obj.Geometry.ToBrep()
else:
brep = obj.Geometry
idx = objref.GeometryComponentIndex.Index
eCrv = brep.Trims[idx].Edge.ToNurbsCurve()
crvLength = round(eCrv.GetLength(), 3)
eIdx = brep.Trims[idx].Edge.EdgeIndex
edge = brep.Edges[eIdx]
faces = [brep.Faces[edge.AdjacentFaces()[n]] for n in range(edge.AdjacentFaces().Count)] #brep face indexes
if faces.Count<2:
def filter_id(rhObject, geometry, componentIndex):
if rhObject.Attributes.ObjectId == brepId:
return False
return True
pass
#Ask for another face to mark
sc.doc.Objects.UnselectAll()
go = Rhino.Input.Custom.GetObject()
go.AcceptNothing(True)
go.GeometryFilter = Rhino.DocObjects.ObjectType.Surface
go.SetCustomGeometryFilter(filter_id)
go.SetCommandPrompt("Select a second surface to mark.")
results = go.Get()
if go.CommandResult()!=Rhino.Commands.Result.Success:
return go.CommandResult()
if go.CommandResult()!=Rhino.Commands.Result.Nothing:
pass
if results == Rhino.Input.GetResult.Object:
objref2 = go.Object(0)
idx2 = objref2.GeometryComponentIndex.Index
if idx2 == -1:
idx2 = 0
faces.append(objref2.Brep().Faces[idx2])
sc.doc.Objects.UnselectAll()
eDom = eCrv.Domain
x = eCrv.ClosestPoint(pPt)
if eCrv.ClosestPoint(pPt)[1]>eDom.Mid:
eCrv.Reverse()
print "Reversed"
while True:
#Get the options for dividing and marking this edge
num = 0
if sc.sticky.has_key("SEW_NUMBER"):
num = sc.sticky["SEW_NUMBER"]
addNum = False
if sc.sticky.has_key("ADD_SEW_NUMBERS"):
addNum = sc.sticky["ADD_SEW_NUMBERS"]
dblSize = 1
if sc.sticky.has_key("SEAM_MARKER_SIZE"):
dblSize = sc.sticky["SEAM_MARKER_SIZE"]
divLen = 1
if sc.sticky.has_key("SEW_DIV_LENGTH"):
divLen = sc.sticky["SEW_DIV_LENGTH"]
divNum = 5
if sc.sticky.has_key("SEW_DIV_NUM"):
divNum = sc.sticky["SEW_DIV_NUM"]
mode = False
if sc.sticky.has_key("SEW_DIV_MODE"):
mode = sc.sticky["SEW_DIV_MODE"]
fontName= "Arial"
if sc.sticky.has_key("SEW_FONTNAME"):
fontName = sc.sticky ["SEW_FONTNAME"].title()
go = Rhino.Input.Custom.GetOption()
go.AcceptNothing(True)
strGo = "Edge length is " + str(crvLength) + " Press Enter to accept the current settings."
go.SetCommandPrompt(strGo)
go.AcceptNumber(True, True)
opSize = Rhino.Input.Custom.OptionDouble(dblSize)
opNum = Rhino.Input.Custom.OptionInteger(num)
opDivLen = Rhino.Input.Custom.OptionDouble(divLen)
opDivNum = Rhino.Input.Custom.OptionInteger(divNum)
opMode = Rhino.Input.Custom.OptionToggle(mode, "Number", "Length")
opAddNum = Rhino.Input.Custom.OptionToggle(addNum, "No", "Yes")
opFont = go.AddOption("Font", fontName)
go.AddOptionToggle("Mode",opMode)
go.AddOptionInteger("CurrentNumber", opNum)
go.AddOptionDouble("MarkerSize", opSize)
#Decide what division option to add
if mode:
go.AddOptionDouble("DivisionLength", opDivLen)
else:
go.AddOptionInteger("DivisionNumber", opDivNum)
go.AddOptionToggle("Numbers", opAddNum)
result = go.Get()
if( go.CommandResult() != Rhino.Commands.Result.Success ):
return
if result == Rhino.Input.GetResult.Number:
# divLen = go.Number()
# sc.sticky["SEW_DIV_LENGTH"] = divLen
divNum = int(go.Number())
sc.sticky["SEW_DIV_NUM"] = divNum
continue
if result == Rhino.Input.GetResult.Nothing:
break
if result == Rhino.Input.GetResult.Option:
opIdx = go.OptionIndex()
if opIdx == opFont:
#fontRC, tempFont = Rhino.Input.RhinoGet.GetString("Font name", True, fontName)
gf = Rhino.Input.Custom.GetString()
gf.SetCommandPrompt("Set new marker font.")
gf.AddOption("List")
fontRC = gf.Get()
if fontRC == Rhino.Input.GetResult.Option:
tempFont = rs.ListBox(fonts, "Set marker font", fonts[fonts.index(fontName)])
else:
tempFont == gf.String()
if tempFont is not None:
if tempFont.lower() in lFonts:
fontName = tempFont
sc.sticky["SEW_FONTNAME"]= fontName.title()
mode = opMode.CurrentValue
dblSize = opSize.CurrentValue
num = opNum.CurrentValue
divLen = opDivLen.CurrentValue
divNum = opDivNum.CurrentValue
addNum = opAddNum.CurrentValue
sc.sticky["ADD_SEW_NUMBERS"] = addNum
sc.sticky["SEW_NUMBER"] = num
sc.sticky["SEAM_MARKER_SIZE"] = dblSize
sc.sticky["SEW_DIV_LENGTH"] = divLen
sc.sticky["SEW_DIV_NUM"] = divNum
sc.sticky["SEW_DIV_MODE"] = mode
continue
#Set the right kind of curve division
if mode:#Use length of division
pars = eCrv.DivideByLength(divLen, True)
else: #Use number of divisions
pars = eCrv.DivideByCount(divNum, True)
for par in pars:
pt = eCrv.PointAt(par)
pts = [eCrv.PointAt(par) for par in pars]
plane = None
intCrvs =[]
grp1 = rs.AddGroup()
grp2 = rs.AddGroup()
for i in range(len(pts)):
pt = pts[i]
if pt: rc, plane = eCrv.PerpendicularFrameAt(eCrv.ClosestPoint(pt)[1])
circle = Rhino.Geometry.Circle(plane, dblSize)
brepCircle = Rhino.Geometry.Brep.CreatePlanarBreps([circle.ToNurbsCurve()]) [0]
srfCircle = brepCircle.Faces[0].DuplicateSurface()
count = 0
for face in faces:
ret, crvs, iPts = Rhino.Geometry.Intersect.Intersection.BrepBrep(face.ToBrep(), brepCircle, .001)
count += 1
if addNum:
directionsMatch=False
if crvs:
srf = face.DuplicateSurface()
intCrvs.append(crvs[0])
if pt.DistanceTo(crvs[0].PointAtStart) < pt.DistanceTo(crvs[0].PointAtEnd):
tPt = crvs[0].PointAtEnd
vecY = crvs[0].TangentAtEnd
else:
tPt = crvs[0].PointAtStart
vecY = crvs[0].TangentAtStart
vecY.Reverse()
srfRc,parU, parV = srf.ClosestPoint(tPt)
planeRc, tPlane = srf.FrameAt(parU, parV)
planeAxis = Rhino.Geometry.Vector3d(tPlane.ZAxis)
planeAxis.Reverse()
vecX= Rhino.Geometry.Vector3d(vecY)
vecX.Rotate( pi/2,planeAxis)
tPlane = Rhino.Geometry.Plane(tPlane.Origin,vecX,vecY)
tPlane.Origin = pt
if Rhino.Geometry.Vector3d.VectorAngle(eCrv.TangentAtStart, tPlane.XAxis) < pi/2:
directionsMatch=True
blnClose = True
if Rhino.DocObjects.Font(fontName).IsSingleStrokeFont: blnClose = False
text = Rhino.Geometry.Curve.CreateTextOutlines(str(num), fontName, .9*dblSize,0, blnClose, tPlane,.8*dblSize, tolerance=.001)
if text:
textBB = Rhino.Geometry.BoundingBox()
for txtCrv in text:
textBB.Union(txtCrv.GetBoundingBox(tPlane))
pass
corners = textBB.GetCorners()
pToP = Rhino.Geometry.Transform.PlaneToPlane(Rhino.Geometry.Plane.WorldXY,tPlane)
for u in range(8):
corners[u] = pToP*corners[u]
#rs.AddPoints([tempPt, tPt])
if directionsMatch:
if count > 1:
if i > 0:
xXform = (pt-corners[1])*1.1
else:
xXform = None
else:
if i > 0:
xXform = (pt-corners[1])*1.1
else:
xXform = None
else:
if count > 1:
if i < len(pts)-1:
xXform = (pt-corners[1])*1.1
else:
xXform = None
else:
if 0< i < len(pts)-1:
xXform = None
elif i == len(pts)-1 :
xXform = None
elif i == 0:
xXform = (pt-corners[1]).Length*eCrv.TangentAtStart*1.1
yXform = tPlane.YAxis*.1*dblSize
tempIds = []
for txtCrv in text:
if xXform is not None:
txtCrv.Translate(xXform)
txtCrv.Translate(yXform)
tempIds.append(sc.doc.Objects.AddCurve(txtCrv))
rs.AddObjectsToGroup(tempIds, rs.AddGroup())
if count ==1:
rs.AddObjectsToGroup(tempIds, grp1)
else:
rs.AddObjectsToGroup(tempIds, grp2)
pass
if ret:
for item in crvs:
id = System.Guid.NewGuid()
crvId = sc.doc.Objects.AddCurve(item)
if count ==1:
rs.AddObjectsToGroup(crvId, grp1)
else:
rs.AddObjectsToGroup(crvId, grp2)
rs.SetUserText(crvId, "SeamMarkerId", str(id))
id = None
Past1 = True
if addNum: num += 1
sc.sticky["SEW_NUMBER"] = num
sc.doc.Views.Redraw()
if __name__ =="__main__": SeamMarkerDivide()
@pgolay
Copy link
Author

pgolay commented Jul 5, 2018

Fixed nothing-added-if-Numbers=No

@pgolay
Copy link
Author

pgolay commented Jul 5, 2018

Modified the text placement, hopefully for the better.

@pgolay
Copy link
Author

pgolay commented Jul 6, 2018

Looks like I broke the thing completely when single surfaces and not joined edges are used.

@pgolay
Copy link
Author

pgolay commented Jul 6, 2018

Fixed for unjoined edges.

@pgolay
Copy link
Author

pgolay commented Jul 6, 2018

Fixed text placement bugs, I think,
Added grouping of all added curves.

@pgolay
Copy link
Author

pgolay commented Jul 20, 2018

Added the ability to select a font for the number output and accommodate single stroke fonts.

@pgolay
Copy link
Author

pgolay commented Jul 21, 2018

Filter single-stroke fonts to the top of the list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment