Site Tools


Show Surface Direction

Developer: .NET
Summary: Demonstrates how to show the direction of surface normals using conduit

Problem

I'm trying to create a function which can show a preview while the user toggles a command option, but I can't seem to get it right. The functionality I want is basically the same as the Flip option in the Direction command, where the result is presented as soon as the option is clicked.

Solution

Here is a sample MRhinoDisplayConduit-inherited conduit class that will draw direction arrows for a surface or polysurface.

C#

/// <summary>
/// TestSurfaceDir Conduit
/// </summary>
public class TestSurfaceDirConduit : MRhinoDisplayConduit
{
  IOnBrep m_brep;
  bool m_bFlip;
  ArrayOn3dPoint m_points;
  ArrayOn3dVector m_normals;
  const int SURFACE_ARROW_COUNT = 5;
 
  public TestSurfaceDirConduit()
    : base(new MSupportChannels(MSupportChannels.SC_DRAWOVERLAY), false)
  {
    m_brep = null;
    m_bFlip = false;
    m_points = new ArrayOn3dPoint();
    m_normals = new ArrayOn3dVector();
  }
 
  public void SetFlip(bool bFlip)
  {
    m_bFlip = bFlip;
  }
 
  public void SetBrep(IOnBrep brep)
  {
    if (null == brep || !brep.IsValid())
      return;
 
    m_brep = brep;
 
    int face_count = m_brep.m_F.Count();
    m_points.Reserve(face_count * SURFACE_ARROW_COUNT * SURFACE_ARROW_COUNT);
    m_normals.Reserve(face_count * SURFACE_ARROW_COUNT * SURFACE_ARROW_COUNT);
 
    m_points.SetCount(0);
    m_normals.SetCount(0);
 
    for (int i = 0; i < face_count; i++)
    {
      IOnBrepFace face = m_brep.m_F[i];
      IOnBrepLoop loop = face.OuterLoop();
      if (null == loop)
        continue;
 
      OnInterval udomain = face.Domain(0);
      OnInterval vdomain = face.Domain(1);
 
      if (loop.m_pbox.IsValid())
      {
        OnInterval domain = new OnInterval();
        domain.Set(loop.m_pbox.m_min.x, loop.m_pbox.m_max.x);
        domain.Intersection(udomain);
        if (domain.IsIncreasing())
          udomain.Set(domain.Min(), domain.Max());
        domain.Set(loop.m_pbox.m_min.y, loop.m_pbox.m_max.y);
        domain.Intersection(vdomain);
        if (domain.IsIncreasing())
          vdomain.Set(domain.Min(), domain.Max());
      }
 
      bool bUntrimmed = m_brep.FaceIsSurface(i);
 
      ArrayOnInterval intervals = new ArrayOnInterval();
      bool bRev = face.m_bRev;
 
      for (double u = 0.0; u < SURFACE_ARROW_COUNT; u += 1.0)
      {
        double d = u / (SURFACE_ARROW_COUNT - 1.0);
        double s = udomain.ParameterAt(d);
 
        intervals.SetCount(0);
 
        if (bUntrimmed || RhUtil.RhinoGetIsoIntervals(face, 1, s, intervals) > 0)
        {
          for (double v = 0.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.Count(); k++)
            {
              if (intervals[k].Includes(t))
                bAdd = true;
            }
 
            if (bAdd)
            {
              On3dPoint pt = new On3dPoint();
              On3dVector du = new On3dVector();
              On3dVector dv = new On3dVector();
              On3dVector dir = new On3dVector();
              if (face.EvNormal(s, t, ref pt, ref du, ref dv, ref dir))
              {
                m_points.Append(pt);
                if (bRev)
                  dir.Reverse();
                m_normals.Append(dir);
              }
            }
          }
        }
      }
    }
  }
 
  public override bool ExecConduit(ref MRhinoDisplayPipeline dp, uint nChannel, ref bool bTerminate)
  {
    if (nChannel == MSupportChannels.SC_DRAWOVERLAY)
    {
      if (null != m_brep)
      {
        MRhinoViewport vp = dp.GetRhinoVP();
        OnColor saved_color = vp.SetDrawColor(RhUtil.RhinoApp().AppSettings().TrackingColor());
        for (int i = 0; i < m_points.Count(); i++)
        {
          if (i % 100 == 0 && vp.InterruptDrawing())
            break;
 
          On3dPoint pt = m_points[i];
          On3dVector dir = new On3dVector(m_normals[i]);
          if (m_bFlip)
            dir.Reverse();
 
          vp.DrawDirectionArrow(pt, dir);
        }
        vp.SetDrawColor(saved_color);
      }
    }
    return true;
  }
}

And, there is an example the above conduit's use.

public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
  MRhinoGetObject go = new MRhinoGetObject();
  go.SetCommandPrompt("Select surface or polysurface for direction display");
  go.SetGeometryFilter(IRhinoGetObject.GEOMETRY_TYPE_FILTER.surface_object | IRhinoGetObject.GEOMETRY_TYPE_FILTER.polysrf_object);
  go.GetObjects(1, 1);
  if (go.CommandResult() != IRhinoCommand.result.success)
    return go.CommandResult();
 
  MRhinoObjRef obj_ref = go.Object(0);
  IOnBrep brep = obj_ref.Brep();
  if (null == brep)
    return IRhinoCommand.result.failure;
 
  bool bIsSolid = brep.IsSolid();
  bool bFlip = false;
 
  TestSurfaceDirConduit conduit = new TestSurfaceDirConduit();
  conduit.SetBrep(brep);
  conduit.Enable();
  context.m_doc.Redraw();
 
  MRhinoGetOption gf = new MRhinoGetOption();
  gf.SetCommandPrompt("Press Enter when done");
  gf.AcceptNothing();
  if (!bIsSolid)
    gf.AddCommandOption(new MRhinoCommandOptionName("Flip"));
 
  for (; ; )
  {
    IRhinoGet.result res = gf.GetOption();
 
    if (res == IRhinoGet.result.option)
    {
      bFlip = !bFlip;
      conduit.SetFlip(bFlip);
      context.m_doc.Redraw();
      continue;
    }
 
    if (res == IRhinoGet.result.nothing)
    {
      if (!bIsSolid && bFlip)
      {
        OnBrep flipped_brep = new OnBrep(brep);
        flipped_brep.Flip();
        context.m_doc.ReplaceObject(obj_ref, flipped_brep);
      }
    }
 
    break;
  }
 
  conduit.Disable();
  context.m_doc.Redraw();
 
  return IRhinoCommand.result.success;
}


developer/showsurfacedir.txt ยท Last modified: 2016/03/22 by sandy