C# text tag 3d / visual studio

trying to implement what text tag 3d component does, but in c# so that i can have text curves in the end (with size parameter and justification) or even better surfaces, but cant seem to find the solution. i dont want to use another plugin because i am building my own functionality, but can’t find a way to create text as geo.

can anybody point me to the right direction?

Hello

you just have to search a bit on the forum, many C# files have been given.

Search for TextEntity

Here are the help for developing.

https://developer.rhino3d.com/api/rhinocommon/rhino

https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.textentity/createsurfaces

And by the way I am not really sure it is the same as Text Tag3d (it is not really geometry there as you can’t bake).

1 Like

Well, if we believe in David (yes we do) it is best practice to use the display pipeline like described in this example:

you can’t bake it though, because you have no output in your RunScript method.

however, you should not confuse it with TextEntity (Text object in RH) that draws the outlines of a font as curves:

using System;
using System.Collections;
using System.Collections.Generic;
using Rhino;
using Rhino.Geometry;
using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
using System.IO;
using System.Linq;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using System.Runtime.InteropServices;
using Rhino.DocObjects;
using Rhino.Collections;
using GH_IO;
using GH_IO.Serialization;    

protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
{
pManager.AddNumberParameter(“size”, “S”, “text size”, GH_ParamAccess.item);
pManager.AddTextParameter(“text”, “T”, “text content”, GH_ParamAccess.item);
pManager.AddPlaneParameter(“plane”, “P”, “position plane”, GH_ParamAccess.item);
}
/// <summary>
    /// Registers all the output parameters for this component.
    /// </summary>
    protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
    {
        pManager.AddCurveParameter("curves", "C", "the font's outline curves", GH_ParamAccess.list);
    }

    /// <summary>
    /// This is the method that actually does the work.
    /// </summary>
    /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
    protected override void SolveInstance(IGH_DataAccess DA)
    {
        double size = new double();
        DA.GetData("size", ref size);

        string text = "";
        DA.GetData("text", ref text);

        Plane pln = new Plane();
        DA.GetData("plane", ref pln);


        if(size == 0) size = 1;

        if(!string.IsNullOrEmpty("Arial") && size > 0 && !string.IsNullOrEmpty(text) && pln.IsValid)
        {

            var te = RhinoDoc.ActiveDoc.Objects.AddText(text, pln, size, "Arial", true, false);
            Rhino.DocObjects.TextObject txt = RhinoDoc.ActiveDoc.Objects.Find(te) as Rhino.DocObjects.TextObject;

            if (txt != null)
            {
                var tt = txt.Geometry as Rhino.Geometry.TextEntity;
                Curve[] tmp = tt.Explode ();
                List<Curve> crvLst = new List<Curve>();
                for (int i = 0; i < tmp.Count(); i++)
                {
                    crvLst.Add(tmp[i]);
                }
                    DA.SetDataList("curves", crvLst);

            }

            RhinoDoc.ActiveDoc.Objects.Delete(te, true);
        }
    }

where you can easily output the curves.

hope this helps at least to understand how it’s supposed to work and where to find the hint you’re looking for.

B

1 Like

thats great but a bit heavy. wondering how ladybug for example draws all their 3d text and then you can bake it as well

Ladybug’s solution is probably even heavier. I think you could peak in it’s code with a decompiler or contact the author if you’re looking for the exact same function.

My code is old and I admit pretty messy, I had made several useless and not logical checks - suppressing them all, the pretty simple core function is this:

var te = RhinoDoc.ActiveDoc.Objects.AddText("myText", pln, size, "Arial", true, false);
            Rhino.DocObjects.TextObject txt = RhinoDoc.ActiveDoc.Objects.Find(te) as Rhino.DocObjects.TextObject;
            if (txt != null)
            {
                var tt = txt.Geometry as Rhino.Geometry.TextEntity;
                Curve[] tmp = tt.Explode ();
                List<Curve> crvLst = new List<Curve>();
                for (int i = 0; i < tmp.Count(); i++) crvLst.Add(tmp[i]);
                DA.SetDataList("curves", crvLst);
            }
            RhinoDoc.ActiveDoc.Objects.Delete(te, true);

Hope this helps.

B

1 Like

You can override the BakeGeometry method to bake anything you want. I would avoid modifying the Rhino Doc in SolveInstance. Just store the Text object results of last SolveInstance in a separate field so you can be access them during Draw and Bake calls.

Here’s an example to display and bake 3D Text as editable text entities (not curves / surfaces!).

        /// This list gets cleared and populated again during each SolveInstance()
        private List<Text3d> TextTags = new List<Text3d>();


        public override void DrawViewportWires(IGH_PreviewArgs args)
        {
            if (this.Locked) 
                return;
            var color = this.Attributes.Selected ? args.WireColour_Selected : args.WireColour;
            this.TextTags.ForEach(text3d =>
            {
                args.Display.Draw3dText(text3d, color);
            });
        }

        public override void BakeGeometry(RhinoDoc doc, ObjectAttributes att, List<Guid> obj_ids)
        {
            att = att ?? doc.CreateDefaultAttributes();
            this.TextTags.ForEach(text3d =>
            {
                var id = doc.Objects.AddText(text3d, att);
                obj_ids.Add(id);
            });
        }
1 Like