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.
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.
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);
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);
});
}