Skip to content

Instantly share code, notes, and snippets.

@pgolay
Created October 29, 2021 21:45
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/bf860e699b17aa614f74d5eb3d127336 to your computer and use it in GitHub Desktop.
Save pgolay/bf860e699b17aa614f74d5eb3d127336 to your computer and use it in GitHub Desktop.
Set the UV direction of planar faces in a brep
import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs
import System
import math
def PlaneAlignedBB(geo, plane):
wxy = Rhino.Geometry.Plane.WorldXY
xform = Rhino.Geometry.Transform.ChangeBasis( wxy, plane)
bb = geo.GetBoundingBox(plane)
box = Rhino.Geometry.Box(bb)
xform = Rhino.Geometry.Transform.ChangeBasis( plane, wxy)
box.Transform(xform)
return box
def PlanarFaceDirection():
pi = math.pi
X_color = Rhino.ApplicationSettings.AppearanceSettings.GridXAxisLineColor
Y_color = Rhino.ApplicationSettings.AppearanceSettings.GridYAxisLineColor
f_color = Rhino.ApplicationSettings.AppearanceSettings.FeedbackColor
tol = sc.doc.ModelAbsoluteTolerance
def GetPointDynamicDrawFunc( sender, args ):
pt = args.CurrentPoint
args.Display.DrawPoint(plane.Origin)
circle = Rhino.Geometry.Circle(plane, dX/2)
args.Display.DrawCircle(circle, f_color, 1)
vecX = pt-plane.Origin
vecY = pt-plane.Origin
vecY.Unitize()
vecLocX = Rhino.Geometry.Vector3d(vecY)
vecY *= dY/2
vecY.Rotate(pi/2, vecZ)
vecY.Unitize()
vecLocY = Rhino.Geometry.Vector3d(vecY)
angle = Rhino.Geometry.Vector3d.VectorAngle( plane.XAxis,vecX, plane)
#textLoc = plane.Origin+vecX/2
textLoc = (circle.Plane.Origin + vecLocX*circle.Radius*1.25)
angle = round(Rhino.RhinoMath.ToDegrees(angle), 2)
#print str(angle)
args.Display.DrawLine(plane.Origin, plane.Origin + (plane.XAxis*dX/2), X_color, 2)
args.Display.DrawLine(plane.Origin, plane.Origin + (plane.YAxis*circle.Radius), Y_color, 4)
args.Display.DrawLine( plane.Origin, plane.Origin + vecX, System.Drawing.Color.Red,4)
args.Display.DrawLine(plane.Origin, plane.Origin + vecY*circle.Radius, System.Drawing.Color.Green, 4)
#args.Display.DrawPoint(textLoc)
args.Display.Draw2dText(str(angle),System.Drawing.Color.AliceBlue, textLoc, False, 20)
def filter_planar( rhino_object, geometry, component_index):
if geometry.IsPlanar():
return True
return False
objRef = rs.GetObject('Select a planar face.', filter = 8, preselect=True, subobjects=True, custom_filter = filter_planar)
if not objRef: return
brep = objRef.Brep()
single=False
if objRef.GeometryComponentIndex.Index == -1:
single = True
face = brep.Faces[0]
else:
face = brep.Faces[objRef.GeometryComponentIndex.Index]
indices = [brep.Faces[n].FaceIndex for n in range(brep.Faces.Count) if brep.Faces[n].FaceIndex != objRef.GeometryComponentIndex.Index ]
id = objRef.ObjectId
outer = face.OuterLoop.To3dCurve()
inner = None
if face.Loops.Count > 1:
inner = [face.Loops[n].To3dCurve() for n in range(1,face.Loops.Count)]
srf = face.UnderlyingSurface()
rc, plane = srf.TryGetPlane()
if not rc:
print('Could not find a plane.')
return
"""
if face.OrientationIsReversed:
plane.Flip()
"""
box = PlaneAlignedBB(srf, plane)
dX = box.X.Length
dY = box.Y.Length
vecZ = plane.ZAxis
plane.Origin = box.Center
cPlane = rs.ViewCPlane()
if plane.ZAxis.IsParallelTo(cPlane.ZAxis) == -1: plane.Flip()
while True:
useCPlaneOrtho = False
if sc.sticky.has_key('USE_CPLANE_ORTHO'):
useCPlaneOrtho = sc.sticky['USE_CPLANE_ORTHO']
gp = Rhino.Input.Custom.GetPoint()
gp.AddOption('CPlane')
opCPlane = Rhino.Input.Custom.OptionToggle(useCPlaneOrtho, 'No', 'Yes')
gp.AddOptionToggle('UseOrtho', opCPlane)
if useCPlaneOrtho:
circle_plane = Rhino.Geometry.Plane(rs.ViewCPlane())
circle_plane.Origin = plane.Origin
else:
circle_plane = plane
gp.Constrain(Rhino.Geometry.Circle(circle_plane, dX/2))
gp.DynamicDraw += GetPointDynamicDrawFunc
rc = gp.Get()
if ( gp.CommandResult() != Rhino.Commands.Result.Success ):
return
elif rc == Rhino.Input.GetResult.Option:
idx = gp.OptionIndex()
if idx ==1:
cplane = sc.doc.Views.ActiveView.ActiveViewport.ConstructionPlane()
cplane.Origin = plane.Origin
pt = cplane.Origin + cplane.XAxis
break
else:
useCPlaneOrtho = opCPlane.CurrentValue
sc.sticky['USE_CPLANE_ORTHO'] = useCPlaneOrtho
continue
elif rc ==Rhino.Input.GetResult.Point:
pt = gp.Point()
break
vecX = pt-plane.Origin
xform = Rhino.Geometry.Transform.Rotation(plane.XAxis, vecX, plane.Origin)
box.Transform(xform)
new_brep = Rhino.Geometry.Brep.CreateTrimmedPlane(box.Plane, outer)
if inner is not None:
for item in inner:
new_brep.Loops.AddPlanarFaceLoop(0, Rhino.Geometry.BrepLoopType.Inner, [item])
if not single:
copyBrep = brep.DuplicateSubBrep(indices)
new_brep.Join(copyBrep, tol, True)
new_brep.Compact()
if new_brep.IsValid:
sc.doc.Objects.Replace(id, new_brep)
sc.doc.Views.Redraw()
if __name__ == '__main__':PlanarFaceDirection()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment