How to wrap a custom geometry in a custom c#/vb component?Thankyou

(Andrealu2012) #1

Hello,i am doing a custom component to contain several custom geometry (for example a custom geometry like a robot arm),when i use this custom component,i the robot arm geometry can appear in the rhino viewport.
how to do that,can you give some advise?thank you!

#2

Implements IGH_PreviewObject in the parameter of your custom geometry and with DrawViewportMeshes() and DrawViewportWires() you can draw your custom display.

(Andrealu2012) #3

thank you,Abalde,but how to add a mesh object to component in Visual studio?

(David Rutten) #4

That’s not possible, components do not have a mechanism for storing data. What you can do is add an output parameter to your component of type Mesh or Brep and send your geometry there.

Another possibility is to create an entirely new data type which represents the entire robot arm, and output that data type instead. I do not know whether that’s something you really need though.

If you only want your component to draw the robot arm shapes in the preview, then you must follow @Dani_Abalde’s advice and override the DrawViewportMeshes() and DrawViewportWires() methods on your component class. From your overrides call the base class, then draw whatever you want in the remainder of the methods. You will also probably have to define some local variables that can contain the robot arm data you want to draw, so that you can assign these from the SolveInstance() method and read them from the DrawViewportXXXX() methods.

(David Rutten) #7

You don’t draw your geometry inside RunScript, you draw it inside the drawing methods. Click on the Eye icon on the script editor toolbar and those methods will be added. You can then re-use the argument instances you’re given.

The RunScript method only runs once per solution, but the drawing must happen for all viewports on every refresh. Here’s what I’d do: rodandballs.gh (6.8 KB)

  private void RunScript(Point3d x, Point3d y, ref object D)
  {
    D = x.DistanceTo(y);

    _balls.Add(Mesh.CreateFromSphere(new Sphere(x, 1.5), 50, 25));
    _balls.Add(Mesh.CreateFromSphere(new Sphere(y, 2.5), 50, 25));

    Circle circle = new Circle(new Plane(x, y - x), 1);
    Cylinder cylinder = new Cylinder(circle, x.DistanceTo(y));
    _rods.Add(Mesh.CreateFromCylinder(cylinder, 1, 50));
  }

  private readonly List<Mesh> _balls = new List<Mesh>();
  private readonly List<Mesh> _rods = new List<Mesh>();
  private BoundingBox _clippingBox;

  /// <summary>
  /// This method will be called once every solution, before any calls to RunScript.
  /// </summary>
  public override void BeforeRunScript()
  {
    // Clear and dispose all meshes.

    foreach (Mesh ball in _balls)
      ball.Dispose();

    foreach (Mesh rod in _rods)
      rod.Dispose();

    _balls.Clear();
    _rods.Clear();
    _clippingBox = BoundingBox.Empty;
  }
  /// <summary>
  /// This method will be called once every solution, after any calls to RunScript.
  /// </summary>
  public override void AfterRunScript()
  {
    // Make sure the clipping box is big enough to contain all our meshes.
    _clippingBox = BoundingBox.Empty;

    foreach (Mesh ball in _balls)
      _clippingBox.Union(ball.GetBoundingBox(false));

    foreach (Mesh rod in _rods)
      _clippingBox.Union(rod.GetBoundingBox(false));
  }

  //Return a BoundingBox that contains all the geometry you are about to draw.
  public override BoundingBox ClippingBox
  {
    get { return _clippingBox; }
  }

  //Draw all meshes in this method.
  public override void DrawViewportMeshes(IGH_PreviewArgs args)
  {
    Rhino.Display.DisplayMaterial ballMaterial = new Rhino.Display.DisplayMaterial(System.Drawing.Color.Gold);
    Rhino.Display.DisplayMaterial rodMaterial = new Rhino.Display.DisplayMaterial(System.Drawing.Color.Gray);

    foreach (Mesh ball in _balls)
      args.Display.DrawMeshShaded(ball, ballMaterial);

    foreach (Mesh rod in _rods)
      args.Display.DrawMeshShaded(rod, rodMaterial);

    ballMaterial.Dispose();
    rodMaterial.Dispose();
  }
(David Rutten) #8

A 3dm file is not a Mesh. It may contain a mesh of course, or a hundred. Or maybe it’s empty. Or maybe it contains curves. The point is, it’s not a mesh.

If you want to embed mesh geometry into your application, you have three options:

  1. Make the mesh from scratch once and cache it. You’re running inside Rhino so you have access to a bunch of geometry functionality and the mesher. This is flexible, doesn’t add a lot of data to your code, and you could even choose to create low-density and high-density meshes. However sometimes the shapes are too difficult to make through code.
  2. Embed a 3dm file as a resource, extract it as a 3dm file, parse the 3dm file and extract whatever objects are in there.
  3. Find some other way to serialize just the mesh shapes. Rhino.Geometry.Mesh implements the ISerializable interface and you can use methods such as Grasshopper.Kernel.GH_Convert.CommonObjectToByteArray() and Grasshopper.Kernel.GH_Convert.ByteArrayToCommonObject() to store meshes as byte[] data. You can then put just those bytes into the resources, so you won’t have to deal with the 3dm file which surrounds the mesh.

You can of course also choose to put a separate 3dm file next to your plugin, and load your data from there. Even more flexible, but it complicates the distribution of your project and you may not want to expose your meshes just like that.

(David Rutten) #10

The panel doesn’t write binary files, it writes text files.

I recommend you do the file writing from within your C# component directly, using System.IO.File.WriteAllBytes().