-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVariableOffsetComponent.cs
More file actions
160 lines (135 loc) · 5.78 KB
/
VariableOffsetComponent.cs
File metadata and controls
160 lines (135 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using System;
using System.Collections.Generic;
using Grasshopper.Kernel;
using Rhino.Geometry;
using VariableOffset.Utilities;
using System.Linq;
using System.Drawing;
using Rhino.Geometry.Intersect;
namespace VariableOffsetComponent
{
public class VariableOffsetComponent : GH_Component
{
private readonly VariableOffsetRhino _variableOffset;
public VariableOffsetComponent()
: base("Variable Edge Offset", "EdgeOffset",
"Offsets each edge of a closed polyline curve by specified amounts",
"Curve", "Util")
{
_variableOffset = new VariableOffsetRhino();
}
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddCurveParameter("Curve", "C", "Closed polyline curve to offset", GH_ParamAccess.item);
pManager.AddNumberParameter("Edge Offsets", "D", "Offset distance per edge", GH_ParamAccess.list);
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddCurveParameter("Offset Curve", "O", "Resulting offset curve", GH_ParamAccess.item);
}
protected override void SolveInstance(IGH_DataAccess DA)
{
Curve inputCurve = null;
List<double> edgeOffsets = new List<double>();
// Get and verify input data
if (!DA.GetData(0, ref inputCurve) || !DA.GetDataList(1, edgeOffsets)) return;
if (inputCurve == null) return;
if (!inputCurve.IsPolyline())
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Input curve must be a polyline.");
return;
}
if (!inputCurve.IsPlanar())
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Input curve must be planar.");
return;
}
if (!inputCurve.IsClosed)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Input curve must be closed.");
return;
}
if (edgeOffsets.Count == 0) return;
// Find curve direction and flip to ensure negative values offset inward
CurveOrientation direction = inputCurve.ClosedCurveOrientation();
if (direction == CurveOrientation.Clockwise)
{
inputCurve.Reverse();
}
// Convert curve to polyline points
var polyline = inputCurve.ToPolyline(0.1, 0.1, 0, 0).ToPolyline();
// Prepare input for variable offset
var inputPoints = new List<Point3d>(polyline);
var paths = new List<List<Point3d>> { inputPoints };
// Apply edge offsets
for (int j = 0; j < edgeOffsets.Count; j++)
{
_variableOffset.SetEdgeOffset(0, j, edgeOffsets[j]);
}
// Execute offset operation
var offsetPaths = _variableOffset.Execute(paths, 0);
// Convert result to curve
if (offsetPaths.Count > 0)
{
var outputPoints = offsetPaths[0];
outputPoints.Add(outputPoints[0]); // Close the curve
var offsetCurve = new PolylineCurve(outputPoints);
Curve outputCurve = null;
List<Point3d> interPoints = new List<Point3d>();
// Find any self intersections and remove smallest islands
CurveIntersections intersections = Intersection.CurveSelf(offsetCurve, 0.001);
List<double> t = new List<double>();
if (intersections.Count > 0)
{
// Split curves
foreach (var param in intersections)
{
// both params are needed to full cut the loops apart
t.Add(param.ParameterA);
t.Add(param.ParameterB);
interPoints.Add(param.PointA2);
}
var splitCurves = offsetCurve.Split(t);
// if crv is closed, add to list
foreach (Curve crv in splitCurves)
{
crv.MakeClosed(0.001);
}
// Sort curves by area size and return the curve with the biggest area
var closedCurvesWithAreas = splitCurves
.Where(curve => curve.IsClosed)
.Select(curve => new
{
Curve = curve,
Area = AreaMassProperties.Compute(curve)?.Area ?? 0
})
.ToList();
outputCurve = closedCurvesWithAreas
.OrderByDescending(x => x.Area)
.First()
.Curve;
}
else
{
outputCurve = offsetCurve;
}
// Set outputs
DA.SetData(0, outputCurve);
}
}
protected override Bitmap Icon
{
get
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
{
var resourceName = assembly.GetManifestResourceNames().Single(n => n.EndsWith("vo.png"));
var stream = assembly.GetManifestResourceStream(resourceName);
if (stream != null) return new System.Drawing.Bitmap(stream);
}
return null;
}
}
public override Guid ComponentGuid => new Guid("1b67ca3a-7ba9-4511-b14e-417503459e7b");
}
}