本博客内容正在持续更新,最后一次更新时间:2020.09.04
【本文重点】
1.查文档:(1) RhinoCommon SDK (2) Grasshopper API
2.专栏地址:专栏:Rhino (Grasshopper) 二次开发 (C#)
【推荐阅读】
1.Grasshopper:有关 Grasshopper 部分知识点和操作欢迎参考 Grasshopper 学习笔记
2.视频教程:本文部分内容来自油管教程 C# Scripting and Plugin Development for Grasshopper
1 Introduction
1.1 C# 电池
下两图展示了 C# 电池 & 双击组件后打卡的窗口
可以看到这个初始代码包含两个输入 (x, y) 一个输出 (a),out 可以理解为为代码本身的输出,例如 print 语句以及报错时生成的 Error 信息
1.1.1 增、删、改组件的输入、输出
增、删:把组件放大后可以看到中间黑色区域的两侧出现了包含 +, - 的条带,此时可以任意增加或删除变量
改:将鼠标移至变量名上,单击右键即可
1.1.2 用 boolean toggle 电池控制 C# 电池是否在每次 recompte 时还原
在双击 C# 电池打开的 C# Editor 中,只有 private void RunScript() {}
这个函数会在每次调用时都执行一遍,这意味着外部定义的变量在每次调用后都会把数值储存起来,等待下次运行时被调用
例如对于包含下图内容的 C# 电池,按五次 F5 or 点击菜单栏 Solution – Recompte 五次,就会输出 A = 5
但怎么去还原 i 的初始值 0 呢? 函数内增加一个 if else,外部增加一个 boolean 输入
这样不管怎按 F5, 输出将一直是 A = 0
1.1.3 用 timer 电池每隔一段时间 recompte 一次 C# 电池
可以看到右边黄色框内数字在快速增加
1.1.n 其他注意事项
- 保证代码窗口右上角的 Shrink Script Editor 处于未激活状态,这样可以避免后续因为窗口缩小以至于被忽视而导致的一系列问题,just trust me
1.2 其他电池
1.2.1 将 Rhino 中创建的几何体赋值给电池
以 Curve 为例,右键单击电池,选择 Set one Curve / Set Mutiple Curves,随后在 Rhino 界面框选目标几何体
1.3 一些简单的 C# 电池示例
1.3.1 使用 for Loop 输出数据到 panel 以及 Rhino 的命令行
private void RunScript(object x, object y, double z, ref object A, ref object B)
{
for (int i = 0; i < 5; i += 1) {
Print(i.ToString());
RhinoApp.WriteLine(i.ToString());
}
}
运行效果:
1.3.2 使用 for + foreach Loop 画几个圆
private void RunScript(object x, object y, double z, ref object A, ref object B)
{
List<Point3d> ps = new List<Point3d>() {};
for(int i = 0; i < 5; i += 1) {
Point3d p = new Point3d(i, i, i);
ps.Add(p);
}
List<Circle> cs = new List<Circle>() {};
foreach(Point3d p in ps) {
double r = 1;
Circle c = new Circle(p, r);
cs.Add(c);
}
A = cs;
}
2 Class of RhinoCommon
本小节内容可能更偏向作者本人接触的一些项目所涉及的内容,其余请参阅官方文档(链接在文章开头部分)
2.1 Data type
2.1.1 Value type
用等号做赋值运算时,相当于创建了一个新的对象
int, double …
Point3d, Vector3d …
Point3d p = new Point3d(x, y, z);
Circle c = new Circle(Point3d, r);
2.1.2 Reference type
用等号做赋值运算时,等号左右两个变量名依旧指向同一个对象(和 Python 一致)
List …
Curve, Brep, Surface …
这一性质意味着,运行 Surface A = B
后,对 B 的改变会同样改变 A。因此该性质往往会引发许多问题,具体问题以及解决措施可以参考 Grasshopper 二次开发 (C#) Part 5 - Tricks, 5.2 深度复制几何体 Deeply Duplicate Geometry
2.2 Parameter
2.2.1 out
Curve Structure Class
以 Method b = c.ClosestPoint(p, t)
为例:
(b: boolean, c: Curve, p: Point3d, t: double)
该方法用于找曲线 c 中最接近点 p 的点,返回
- 一个 boolean (true 即存在这样的一个最近点,false 即不存在)
- 一个系数值 t (如果 boolean 为真,则将最近点在曲线 c 上的系数值赋给 t)
double t;
boolean success = c.ClosestPoint(p, out t);
if (success)
c.PointAt(t);
关于这个系数值 t 我也没懂其具体含义,恳请了解的大佬留个言。
不过虽然不理解,我们依旧可以使用 t 来实现一些基础的工作:例如,如果要找具体某个点的位置,such as1/4 点,可以这样做
// 获取两个端点的 t 值
double tStart; // tStart 一般为 0
double tEnd;
curve.ClosestPoint(curve.PointAtStart, out tStart);
curve.ClosestPoint(curve.PointAtEnd, out tEnd);
// 获取 1/4 点
double tMid = 0.25 * (tEnd - tStart);
Point3d targetPoint = curve.PointAt(tMid);
3 Data Structure
DataTree 见文档
dt.AllData() 将树中的内容合并到一个 list 中
Examples
1 将曲线分割成线段
根据已知曲线以及设定的 tolerance,将曲线分割成一个线段 list
tolerance > max{ 最短距离 between 分割后各线段的中点 & 已知曲线) }
private void RunScript(Curve curve, double tolerance, ref object A)
{
// 获取曲线两点端点的系数 tStart, tEnd
double tStart;
double tEnd;
curve.ClosestPoint(curve.PointAtStart, out tStart);
curve.ClosestPoint(curve.PointAtEnd, out tEnd);
List<LineCurve> segments = new List<LineCurve>() {};
// 分割函数
DevideCurve(curve, tStart, tEnd, tolerance, segments);
A = segments;
}
public void DevideCurve(Curve curve, double tStart, double tEnd, double tolerance, List<LineCurve> segments)
{
Point3d startPoint = curve.PointAt(tStart);
Point3d endPoint = curve.PointAt(tEnd);
Point3d midPoint = 0.5 * (startPoint + endPoint);
double tClosest; // 最近点的系数
curve.ClosestPoint(midPoint, out tClosest);
double distance = curve.PointAt(tClosest).DistanceTo(midPoint); // 最短距离
if (distance < tolerance)
segments.Add(new LineCurve(startPoint, endPoint));
else
{
double tMid = 0.5 * (tStart + tEnd);
DevideCurve(curve, tStart, tMid, tolerance, segments); // 递归
DevideCurve(curve, tMid, tEnd, tolerance, segments);
}
}
tolerance = 0.9 & 0.2