Hey all,
I am trying to implement a custom datatype and parameter in the context of some plug-in development (C#).
Main problem is to handle the preview of geometry for the parameter. I have custom class holding some points and some colors as geometric objects. Further i implemented a Data_class driven from GH_GeometricGoo and implemented IGH_PreviewData interface. So far working quite well - when put my custom type inside a Geo-Param i get the correct geometry preview. The i implemented a Param class driven from GH_Param<Data_class> and tried to implement IGH_PreviewObject and i can make it work so far that i don’t get amy compiler errors but i can’t get why my parameter isn’t able to create a preview and didn’t even seem to be capable of previewing data (No hide-option in the component-menu of the parameter).
Here is the code of my classes. I hope anybody can help out - thanks a lot!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Rhino.Geometry;
using System.Drawing;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Types;
namespace MCSculpting
{
/// <summary>
/// TrajectoryPtCloud - Object representing the trajectory of a marker as pointcloud.
/// </summary>
public class TrajectoryPtCloud
{
/// <summary>
/// Variable storing the name of the trajoctory/ marker.
/// </summary>
public string markerName { get; private set; }
/// <summary>
/// List storing all points describing the trajectory.
/// </summary>
public List<Point3d> points { get; private set; }
/// <summary>
/// A list containg all frame-numbers of the captured data.
/// </summary>
public List<int> frames { get; private set; }
/// <summary>
/// An optional list of colors assigned to the pointcloud.
/// </summary>
public List<Color> colors { get; private set; }
#region Constructors
/// <summary>
/// Empty Constructor.
/// </summary>
public TrajectoryPtCloud()
{
this.markerName = "unknown";
this.points = new List<Point3d>();
this.frames = new List<int>();
this.colors = new List<Color>();
}
/// <summary>
/// Constructor from marker name and lsit of points.
/// </summary>
/// <param name="marker"> The name of the marker or label of the trajectory.</param>
/// <param name="pts">A list of points describing the trajectory - order matters and is respected.</param>
public TrajectoryPtCloud( string marker, List<Point3d> pts, List<int> frames)
{
if(pts.Count == frames.Count)
{
this.markerName = marker;
this.points = pts;
this.frames = frames;
this.colors = new List<Color>();
}
else
{
throw new IndexOutOfRangeException("The number of frames dosen't match the number of points");
}
}
#endregion
/// <summary>
/// Add a point at the end of the current pointlist describing thr trajectory.
/// </summary>
/// <param name="pt"> The point to add at the end of the trajectory.</param>
public void addPoint(Point3d pt)
{
this.points.Add(pt);
}
/// <summary>
/// Assigning a list of colors to the trajectory in order to map results on the pointcloud.
/// </summary>
/// <param name="colors">List of colors to assign. Must match the number of points in the pointcloud.</param>
public void addColors(List<Color> colors)
{
if(this.points.Count == colors.Count)
{
this.colors = colors;
}
else
{
throw new IndexOutOfRangeException("The number of colors dosen't match the number of points");
}
}
}
/// <summary>
/// Implementation of GH_Data und GH_Param in order to use MCData as custom datatype in grasshopper.
/// </summary>
#region Implement as GH_Parameter
public class Data_TrajectoryPtCloud : GH_GeometricGoo<TrajectoryPtCloud>, IGH_PreviewData
{
#region Constructors
public Data_TrajectoryPtCloud() : base() { }
public Data_TrajectoryPtCloud(TrajectoryPtCloud cloud)
{
this.Value = cloud;
}
public override Grasshopper.Kernel.Types.IGH_Goo Duplicate()
{
//TODO: implement proper duplication...
//ProcessStep copy = null; //Value.DuplicateTopology();
//return new ProcessStep(copy);
return null;
}
#endregion
#region IGH_Goo Members
public override bool IsValid
{
//TODO: implement proper validation...
get { return true; }
}
public override string TypeName
{
get { return "Trajectory Pointcloud"; }
}
public override string TypeDescription
{
get { return "Holds the trajectory of a given marker as pointcloud"; }
}
public override string ToString()
{
return "Trajectory: " + Value.markerName + "; [Points:" + Value.points.Count.ToString() + "]";
}
public override IGH_GeometricGoo DuplicateGeometry()
{
//ToDo: Implement proper Duplicate function
return new Data_TrajectoryPtCloud();
}
public override BoundingBox Boundingbox
{
get
{
BoundingBox box = new BoundingBox(Value.points);
return box;
}
}
public override IGH_GeometricGoo Morph(SpaceMorph xmorph)
{
List<Point3d> pts = new List<Point3d>();
for(var i = 0; i < Value.points.Count; i++)
{
pts.Add(xmorph.MorphPoint(Value.points[i]));
}
TrajectoryPtCloud cloud = new TrajectoryPtCloud(Value.markerName, pts, Value.frames);
cloud.addColors(Value.colors);
return new Data_TrajectoryPtCloud(cloud);
}
public override IGH_GeometricGoo Transform(Transform xform)
{
List<Point3d> pts = new List<Point3d>();
for (var i = 0; i < Value.points.Count; i++)
{
Value.points[i].Transform(xform);
pts.Add(Value.points[i]);
}
TrajectoryPtCloud cloud = new TrajectoryPtCloud(Value.markerName, pts, Value.frames);
cloud.addColors(Value.colors);
return new Data_TrajectoryPtCloud(cloud);
}
public override BoundingBox GetBoundingBox(Transform xform)
{
List<Point3d> pts = new List<Point3d>();
for (var i = 0; i < Value.points.Count; i++)
{
Value.points[i].Transform(xform);
pts.Add(Value.points[i]);
}
TrajectoryPtCloud cloud = new TrajectoryPtCloud(Value.markerName, pts, Value.frames);
cloud.addColors(Value.colors);
BoundingBox box = new BoundingBox(cloud.points);
return box;
}
// This function is called when Grasshopper needs to convert other data into ProcessSteps.
public override bool CastFrom(object source)
{
//Abort immediately on bogus data.
if (source == null) { return false; }
// subclasses need to be converted to baseclass
if (source is TrajectoryPtCloud trajectoryPtCloud)
{
this.Value = trajectoryPtCloud;
return true;
}
//We've exhausted the possible conversions, it seems that source cannot be converted into a ProcessStep after all.
return false;
}
// This function is called when Grasshopper needs to convert this
// instance of ProcessStep into some other type Q.
public override bool CastTo<Q>(ref Q target)
{
//Q is String
if (typeof(Q).IsAssignableFrom(typeof(TrajectoryPtCloud)))
{
object ptr = this.Value;
target = (Q)ptr;
return true;
}
/*
//Then, see if Q is similar to the GH_Integer type.
if (typeof(Q).IsAssignableFrom(typeof(GH_Integer)))
{
object ptr = new GH_Integer(this.Value);
target = (Q)ptr;
return true;
}
*/
//We could choose to also handle casts to Boolean, GH_Boolean,
//Double and GH_Number, but this is left as an exercise for the reader.
return false;
}
#endregion
#region IGH_PreviewData
public BoundingBox ClippingBox
{
get { return this.Boundingbox; }
}
public void DrawViewportWires(GH_PreviewWireArgs args)
{
for (var i = 0; i < Value.points.Count; i++)
{
if (Value.colors.Count != 0)
{
args.Pipeline.DrawPoint(Value.points[i], Rhino.Display.PointStyle.Triangle,5, Value.colors[i]);
}
else
{
args.Pipeline.DrawPoint(Value.points[i], Color.White);
}
}
}
public void DrawViewportMeshes(GH_PreviewMeshArgs args) { }
#endregion
}
public class Param_TrajectoryPtCloud : GH_Param<Data_TrajectoryPtCloud>, IGH_PreviewObject
{
public Param_TrajectoryPtCloud()
: base(new GH_InstanceDescription("trj", "Trajectory Pointcloud", "Holds the trajectory of a given marker as pointcloud.", "MCSculpting", "Params"))
{
}
#region IGH_PreviewObject
bool IGH_PreviewObject.Hidden { get; set; }
bool IGH_PreviewObject.IsPreviewCapable { get; }
BoundingBox IGH_PreviewObject.ClippingBox { get; }
void IGH_PreviewObject.DrawViewportWires(IGH_PreviewArgs args){}
void IGH_PreviewObject.DrawViewportMeshes(IGH_PreviewArgs args){}
#endregion
public override Guid ComponentGuid
{
get { return new Guid("a08e1c20-1e45-40e7-a323-e6f0a56a882e"); }
}
public override GH_Exposure Exposure
{
get
{
return GH_Exposure.primary;
}
}
}
#endregion
}
TrajectoryPtCloud.cs (9.9 KB)