Last active
July 21, 2018 03:40
-
-
Save pgolay/eda7e0476b08c93a952c16c21be191ed 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 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() |
Modified the text placement, hopefully for the better.
Looks like I broke the thing completely when single surfaces and not joined edges are used.
Fixed for unjoined edges.
Fixed text placement bugs, I think,
Added grouping of all added curves.
Added the ability to select a font for the number output and accommodate single stroke fonts.
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
Fixed nothing-added-if-Numbers=No