Sometimes Silhouette.ComputeDraftCurve creates curves that deviate from a BrepFace more than the tolerance argument. For example, the 45° draft curve created on the face in
Silhouette_ComputeDraftCurve_dist_error.3dm (38.0 KB)
with tolerance=0.001, can be pulled to the same face about 0.055.
This occurs in both V7 and V8.2, and also via _DraftAngleAnalysis.
Here is a Python script I've been using to study this.
from __future__ import absolute_import, division, print_function, unicode_literals
import Rhino
import Rhino.DocObjects as rd
import Rhino.Geometry as rg
import scriptcontext as sc
draftAngle = Rhino.RhinoMath.ToRadians(45.0)
tolerance = sc.doc.ModelAbsoluteTolerance
def doesCurveSelfIntersect(rgC, tolerance=None):
if tolerance is None: tolerance = sc.doc.ModelAbsoluteTolerance
rc = rg.Intersect.Intersection.CurveSelf(rgC, tolerance)
return bool(rc)
def create_hi_def_pull_to_face(face, rgC_on_face, tolerance=1e-6):
pulled = rgC_on_face.PullToBrepFace(face=face, tolerance=tolerance)
if len(pulled) == 1:
return pulled[0]
pullback = face.Pullback(rgC_on_face, tolerance=tolerance)
pushup = face.Pushup(pullback, tolerance=tolerance)
return pushup
def main():
res, objrefs = Rhino.Input.RhinoGet.GetMultipleObjects(
prompt="Select breps",
acceptNothing=False,
filter=rd.ObjectType.Brep)
if res != Rhino.Commands.Result.Success: return
attr_Red = rd.ObjectAttributes()
attr_Red.LayerIndex = sc.doc.Layers.CurrentLayerIndex
attr_Red.ColorSource = rd.ObjectColorSource.ColorFromObject
attr_Red.ObjectColor = attr_Red.ObjectColor.Red
attr_Green = attr_Red.Duplicate()
attr_Green.ObjectColor = attr_Green.ObjectColor.Lime
Rhino.RhinoApp.SetCommandPrompt("Working ...")
print("Tolerance: {}".format(tolerance))
for objref in objrefs:
face_In = objref.Face()
if face_In is None:
brep = objref.Brep()
faces = brep.Faces
else:
faces = [face_In]
for face in faces:
srf = face.UnderlyingSurface()
ss = []
silhouettes = rg.Silhouette.ComputeDraftCurve(
geometry=face,
draftAngle=draftAngle,
pullDirection=rg.Vector3d.ZAxis,
tolerance=tolerance,
angleToleranceRadians=sc.doc.ModelAngleToleranceRadians)
for silh in silhouettes:
if silh.Curve is None: continue
if silh.SilhouetteType not in (rg.SilhouetteType.DraftCurve, rg.SilhouetteType.Tangent):
continue
fLength = silh.Curve.GetLength()
if fLength < tolerance:
continue
if doesCurveSelfIntersect(silh.Curve, tolerance):
continue
hi_def_pull = create_hi_def_pull_to_face(face, silh.Curve)
if doesCurveSelfIntersect(hi_def_pull):
continue
bSuccess, fDistMax = rg.Curve.GetDistancesBetweenCurves(
silh.Curve, hi_def_pull, tolerance=0.1*tolerance)[:2]
if not bSuccess:
continue
ss.append(" Max. dist. from face: {}".format(fDistMax))
if fDistMax > tolerance:
ss[-1] += " <-"
sc.doc.Objects.AddCurve(silh.Curve, attr_Red)
sc.doc.Objects.AddCurve(hi_def_pull, attr_Green)
if ss: print('\n'.join(ss))
sc.doc.Views.Redraw()
if __name__ == '__main__': main()
My workaround in another script is to check whether the curve is within tolerance on the face, and pull it to the face when it isn’t. I have not checked whether the curve is pulled to the target draftAngle.