Show Surface Direction

Demonstrates how to show a surface's direction using a display conduit.

partial class Examples
{
  public static Rhino.Commands.Result ShowSurfaceDirection(Rhino.RhinoDoc doc)
  {
    Rhino.DocObjects.ObjRef objref;
    var rc = Rhino.Input.RhinoGet.GetOneObject("Select surface or polysurface for direction display",
      false,
      Rhino.DocObjects.ObjectType.Surface | Rhino.DocObjects.ObjectType.PolysrfFilter,
      out objref);
    if (rc != Rhino.Commands.Result.Success)
      return rc;

    var brep = objref.Brep();
    if (brep == null)
      return Rhino.Commands.Result.Failure;

    bool bIsSolid = brep.IsSolid;

    TestSurfaceDirConduit conduit = new TestSurfaceDirConduit(brep);
    conduit.Enabled = true;
    doc.Views.Redraw();

    var gf = new Rhino.Input.Custom.GetOption();
    gf.SetCommandPrompt("Press enter when done");
    gf.AcceptNothing(true);
    if (!bIsSolid)
      gf.AddOption("Flip");

    for (; ; )
    {
      var res = gf.Get();
      if (res == Rhino.Input.GetResult.Option)
      {
        conduit.Flip = !conduit.Flip;
        doc.Views.Redraw();
        continue;
      }
      if (res == Rhino.Input.GetResult.Nothing)
      {
        if (!bIsSolid && conduit.Flip)
        {
          brep.Flip();
          doc.Objects.Replace(objref, brep);
        }
      }
      break;
    }

    conduit.Enabled = false;
    doc.Views.Redraw();
    return Rhino.Commands.Result.Success;
  }
}

class TestSurfaceDirConduit : Rhino.Display.DisplayConduit
{
  readonly Brep m_brep;
  readonly List<Point3d> m_points;
  readonly List<Vector3d> m_normals;

  public TestSurfaceDirConduit(Brep brep)
  {
    m_brep = brep;
    Flip = false;

    const int SURFACE_ARROW_COUNT = 5;
    int face_count = m_brep.Faces.Count;
    int capacity = face_count * SURFACE_ARROW_COUNT * SURFACE_ARROW_COUNT;
    m_points = new List<Point3d>(capacity);
    m_normals = new List<Vector3d>(capacity);

    for (int i = 0; i < face_count; i++)
    {
      var face = brep.Faces[i];
      var loop = face.OuterLoop;
      if (loop == null)
        continue;

      var udomain = face.Domain(0);
      var vdomain = face.Domain(1);
      var loop_bbox = loop.GetBoundingBox(true);
      if (loop_bbox.IsValid)
      {
        Interval domain = new Interval(loop_bbox.Min.X, loop_bbox.Max.X);
        domain = Interval.FromIntersection(domain, udomain);
        if (domain.IsIncreasing)
          udomain = domain;
        domain = new Interval(loop_bbox.Min.Y, loop_bbox.Max.Y);
        domain = Interval.FromIntersection(domain, vdomain);
        if (domain.IsIncreasing)
          vdomain = domain;
      }

      bool bUntrimmed = face.IsSurface;
      bool bRev = face.OrientationIsReversed;
      for (double u = 0; u < SURFACE_ARROW_COUNT; u += 1.0)
      {
        double d = u / (SURFACE_ARROW_COUNT - 1.0);
        double s = udomain.ParameterAt(d);

        var intervals = face.TrimAwareIsoIntervals(1, s);
        if (bUntrimmed || intervals.Length > 0)
        {
          for (double v = 0; v < SURFACE_ARROW_COUNT; v += 1.0)
          {
            d = v / (SURFACE_ARROW_COUNT - 1.0);
            double t = vdomain.ParameterAt(d);
            bool bAdd = bUntrimmed;
            for (int k = 0; !bAdd && k < intervals.Length; k++)
            {
              if (intervals[k].IncludesParameter(t))
                bAdd = true;
            }
            if (bAdd)
            {
              var pt = face.PointAt(s, t);
              var vec = face.NormalAt(s, t);
              m_points.Add(pt);
              if (bRev)
                vec.Reverse();
              m_normals.Add(vec);
            }
          }
        }
      }
    }
  }

  public bool Flip { get; set; }

  protected override void DrawOverlay(Rhino.Display.DrawEventArgs e)
  {
    if (m_points.Count > 0)
    {
      var color = Rhino.ApplicationSettings.AppearanceSettings.TrackingColor;
      for (int i = 0; i < m_points.Count; i++)
      {
        if (i % 100 == 0 && e.Display.InterruptDrawing())
          break;

        var pt = m_points[i];
        var dir = m_normals[i];
        if (Flip)
          dir.Reverse();
        e.Display.DrawDirectionArrow(pt, dir, color);
      }
    }
  }
}
Partial Friend Class Examples
  Public Shared Function ShowSurfaceDirection(ByVal doc As Rhino.RhinoDoc) As Rhino.Commands.Result
	Dim objref As Rhino.DocObjects.ObjRef = Nothing
	Dim rc = Rhino.Input.RhinoGet.GetOneObject("Select surface or polysurface for direction display", False, Rhino.DocObjects.ObjectType.Surface Or Rhino.DocObjects.ObjectType.PolysrfFilter, objref)
	If rc IsNot Rhino.Commands.Result.Success Then
	  Return rc
	End If

	Dim brep = objref.Brep()
	If brep Is Nothing Then
	  Return Rhino.Commands.Result.Failure
	End If

	Dim bIsSolid As Boolean = brep.IsSolid

	Dim conduit As New TestSurfaceDirConduit(brep)
	conduit.Enabled = True
	doc.Views.Redraw()

	Dim gf = New Rhino.Input.Custom.GetOption()
	gf.SetCommandPrompt("Press enter when done")
	gf.AcceptNothing(True)
	If Not bIsSolid Then
	  gf.AddOption("Flip")
	End If

	Do
	  Dim res = gf.Get()
	  If res Is Rhino.Input.GetResult.Option Then
		conduit.Flip = Not conduit.Flip
		doc.Views.Redraw()
		Continue Do
	  End If
	  If res Is Rhino.Input.GetResult.Nothing Then
		If Not bIsSolid AndAlso conduit.Flip Then
		  brep.Flip()
		  doc.Objects.Replace(objref, brep)
		End If
	  End If
	  Exit Do
	Loop

	conduit.Enabled = False
	doc.Views.Redraw()
	Return Rhino.Commands.Result.Success
  End Function
End Class

Friend Class TestSurfaceDirConduit
	Inherits Rhino.Display.DisplayConduit

  Private ReadOnly m_brep As Brep
  Private ReadOnly m_points As List(Of Point3d)
  Private ReadOnly m_normals As List(Of Vector3d)

  Public Sub New(ByVal brep As Brep)
	m_brep = brep
	Flip = False

	Const SURFACE_ARROW_COUNT As Integer = 5
	Dim face_count As Integer = m_brep.Faces.Count
	Dim capacity As Integer = face_count * SURFACE_ARROW_COUNT * SURFACE_ARROW_COUNT
	m_points = New List(Of Point3d)(capacity)
	m_normals = New List(Of Vector3d)(capacity)

	For i As Integer = 0 To face_count - 1
	  Dim face = brep.Faces(i)
	  Dim [loop] = face.OuterLoop
	  If [loop] Is Nothing Then
		Continue For
	  End If

	  Dim udomain = face.Domain(0)
	  Dim vdomain = face.Domain(1)
	  Dim loop_bbox = [loop].GetBoundingBox(True)
	  If loop_bbox.IsValid Then
		Dim domain As New Interval(loop_bbox.Min.X, loop_bbox.Max.X)
		domain = Interval.FromIntersection(domain, udomain)
		If domain.IsIncreasing Then
		  udomain = domain
		End If
		domain = New Interval(loop_bbox.Min.Y, loop_bbox.Max.Y)
		domain = Interval.FromIntersection(domain, vdomain)
		If domain.IsIncreasing Then
		  vdomain = domain
		End If
	  End If

	  Dim bUntrimmed As Boolean = face.IsSurface
	  Dim bRev As Boolean = face.OrientationIsReversed
	  For u As Double = 0 To SURFACE_ARROW_COUNT - 1 Step 1.0
		Dim d As Double = u / (SURFACE_ARROW_COUNT - 1.0)
		Dim s As Double = udomain.ParameterAt(d)

		Dim intervals = face.TrimAwareIsoIntervals(1, s)
		If bUntrimmed OrElse intervals.Length > 0 Then
		  For v As Double = 0 To SURFACE_ARROW_COUNT - 1 Step 1.0
			d = v / (SURFACE_ARROW_COUNT - 1.0)
			Dim t As Double = vdomain.ParameterAt(d)
			Dim bAdd As Boolean = bUntrimmed
			Dim k As Integer = 0
			Do While Not bAdd AndAlso k < intervals.Length
			  If intervals(k).IncludesParameter(t) Then
				bAdd = True
			  End If
				k += 1
			Loop
			If bAdd Then
			  Dim pt = face.PointAt(s, t)
			  Dim vec = face.NormalAt(s, t)
			  m_points.Add(pt)
			  If bRev Then
				vec.Reverse()
			  End If
			  m_normals.Add(vec)
			End If
		  Next v
		End If
	  Next u
	Next i
  End Sub

  Public Property Flip() As Boolean

  Protected Overrides Sub DrawOverlay(ByVal e As Rhino.Display.DrawEventArgs)
	If m_points.Count > 0 Then
	  Dim color = Rhino.ApplicationSettings.AppearanceSettings.TrackingColor
	  For i As Integer = 0 To m_points.Count - 1
		If i Mod 100 = 0 AndAlso e.Display.InterruptDrawing() Then
		  Exit For
		End If

		Dim pt = m_points(i)
		Dim dir = m_normals(i)
		If Flip Then
		  dir.Reverse()
		End If
		e.Display.DrawDirectionArrow(pt, dir, color)
	  Next i
	End If
  End Sub
End Class
# No Python sample available