Skip to content

Commit e157fe8

Browse files
committed
General Completion - first state
Known issues include curve offset side detection - could add as a manual input
1 parent c92f483 commit e157fe8

File tree

4 files changed

+270
-9
lines changed

4 files changed

+270
-9
lines changed

OffsetHandler.cs

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Rhino;
7+
using Rhino.Geometry;
8+
using Rhino.Collections;
9+
10+
namespace QuadHyp
11+
{
12+
public class OffsetHandler
13+
{
14+
public Polyline polyline;
15+
public double distance;
16+
public double maxAllowableDistance;
17+
public double minApertureRatio;
18+
public bool inputCurveIsValid = false;
19+
public bool offsetSuccessful = false;
20+
21+
double area;
22+
23+
List<Line> lines = new List<Line>();
24+
List<double> angles = new List<double>();
25+
List<Point3d> points = new List<Point3d>();
26+
List<Point3d> resultPoints = new List<Point3d>();
27+
List<Line> resultLines = new List<Line>();
28+
List<Polyline> resultPolylines = new List<Polyline>();
29+
List<Mesh> resultMeshes = new List<Mesh>();
30+
31+
32+
public OffsetHandler()
33+
{
34+
//
35+
}
36+
37+
public OffsetHandler(Polyline _polyline, double _distance, double _minApertureRatio)
38+
{
39+
polyline = _polyline;
40+
distance = _distance;
41+
minApertureRatio = _minApertureRatio;
42+
43+
for (int i = 0; i < (polyline.Count - 1); i++)
44+
{
45+
points.Add(polyline[i]);
46+
}
47+
48+
foreach (Line line in polyline.GetSegments())
49+
{
50+
lines.Add(line);
51+
}
52+
53+
int count = polyline.Count;
54+
if ((count <= 6) & (count >= 4))
55+
{
56+
inputCurveIsValid = true;
57+
CalculateMaxAllowableDistance();
58+
}
59+
60+
}
61+
62+
void CalculateMaxAllowableDistance()
63+
{
64+
AreaMassProperties AMP = AreaMassProperties.Compute(polyline.ToNurbsCurve());
65+
area = AMP.Area;
66+
maxAllowableDistance = area * (1 - minApertureRatio) / polyline.Length;
67+
if (distance > maxAllowableDistance)
68+
{
69+
offsetSuccessful = false;
70+
return;
71+
}
72+
else
73+
{
74+
offsetSuccessful = GenerateOffset();
75+
}
76+
}
77+
78+
bool GenerateOffset()
79+
{
80+
double crossProductResult = Vector3d.CrossProduct(new Vector3d(- lines[0].From + lines[0].To), new Vector3d(- lines[0].From + lines[1].To)).Z;
81+
LineSide side = (crossProductResult > 0) ? LineSide.Right : LineSide.Left;
82+
double rotateAngleCorrection = (side == LineSide.Left) ? - 1.0 : + 1.0;
83+
//TODO still problem with deciding side
84+
85+
angles.Add(Math.PI - LineLineAngle(lines[lines.Count - 1], lines[0]));
86+
for (int i = 0; i < (lines.Count - 1); i++)
87+
{
88+
angles.Add(Math.PI - LineLineAngle(lines[i], lines[i + 1]));
89+
}
90+
91+
for (int i = 0; i < points.Count; i++)
92+
{
93+
int linesIndex = (i - 1 >= 0) ? (i - 1) : (points.Count - 1);
94+
Vector3d direction = new Vector3d(lines[linesIndex].To - lines[linesIndex].From);
95+
direction.Unitize();
96+
direction.Rotate(rotateAngleCorrection * (Math.PI - 0.5 * angles[i]), Vector3d.ZAxis);
97+
direction = direction * (distance / Math.Sin(angles[i] / 2));
98+
resultPoints.Add(points[i] + direction);
99+
}
100+
101+
for (int i = 0; i < (resultPoints.Count - 1); i++)
102+
{
103+
Line line = new Line(resultPoints[i + 1], resultPoints[i]);
104+
resultLines.Add(line);
105+
}
106+
resultLines.Add(new Line(resultPoints[0], resultPoints[resultPoints.Count - 1]));
107+
108+
109+
return true;
110+
}
111+
112+
double LineLineAngle(Line line1, Line line2)
113+
{
114+
Vector3d vec1 = new Vector3d(line1.To - line1.From);
115+
Vector3d vec2 = new Vector3d(line2.To - line2.From);
116+
return Vector3d.VectorAngle(vec1, vec2);
117+
}
118+
119+
public bool GetResultLines(out List<Line> result)
120+
{
121+
if (offsetSuccessful)
122+
{
123+
result = resultLines;
124+
return offsetSuccessful;
125+
} else
126+
{
127+
result = lines;
128+
return offsetSuccessful;
129+
}
130+
131+
}
132+
133+
public bool GetResultPolylines(out List<Polyline> result)
134+
{
135+
if (offsetSuccessful)
136+
{
137+
//Mesh mesh = new Mesh();
138+
for (int i = 0; i < lines.Count; i++)
139+
{
140+
resultPolylines.Add(
141+
new Polyline(
142+
new List<Point3d>(){
143+
lines[i].From,
144+
lines[i].To,
145+
resultLines[i].From,
146+
resultLines[i].To,
147+
lines[i].From
148+
}));
149+
}
150+
result = resultPolylines;
151+
return offsetSuccessful;
152+
}
153+
else
154+
{
155+
resultPolylines.Add(polyline);
156+
result = resultPolylines;
157+
return offsetSuccessful;
158+
}
159+
}
160+
161+
162+
163+
public bool GenerateMeshFromPolyLine(Polyline plyln, out Mesh mesh)
164+
{
165+
mesh = new Mesh();
166+
if (plyln.Count == 4)
167+
{
168+
mesh.Vertices.Add(plyln[0]);
169+
mesh.Vertices.Add(plyln[1]);
170+
mesh.Vertices.Add(plyln[2]);
171+
mesh.Faces.AddFace(0, 1, 2);
172+
return true;
173+
} else if (plyln.Count == 5)
174+
{
175+
mesh.Vertices.Add(plyln[0]);
176+
mesh.Vertices.Add(plyln[1]);
177+
mesh.Vertices.Add(plyln[2]);
178+
mesh.Vertices.Add(plyln[3]);
179+
mesh.Faces.AddFace(0, 1, 2, 3);
180+
return true;
181+
} else if (plyln.Count == 6)
182+
{
183+
mesh.Vertices.Add(plyln[0]);
184+
mesh.Vertices.Add(plyln[1]);
185+
mesh.Vertices.Add(plyln[2]);
186+
mesh.Vertices.Add(plyln[3]);
187+
mesh.Vertices.Add(plyln[4]);
188+
mesh.Faces.AddFace(0, 1, 4);
189+
mesh.Faces.AddFace(2, 3, 4);
190+
return true;
191+
} else if (plyln.Count == 7)
192+
{
193+
mesh.Vertices.Add(plyln[0]);
194+
mesh.Vertices.Add(plyln[1]);
195+
mesh.Vertices.Add(plyln[2]);
196+
mesh.Vertices.Add(plyln[3]);
197+
mesh.Vertices.Add(plyln[4]);
198+
mesh.Vertices.Add(plyln[5]);
199+
mesh.Faces.AddFace(0, 1, 4, 5);
200+
mesh.Faces.AddFace(1, 2, 3, 4);
201+
return true;
202+
} else
203+
{
204+
return false;
205+
}
206+
207+
208+
}
209+
210+
211+
212+
}
213+
}

QuadHyp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
</ItemGroup>
5858
<ItemGroup>
5959
<Compile Include="LineLineAnalyticalIntersection2d.cs" />
60+
<Compile Include="OffsetHandler.cs" />
6061
<Compile Include="PolygonPolygonAnalyticalIntersection2d.cs" />
6162
<Compile Include="QuadHypComponent.cs" />
6263
<Compile Include="QuadHypInfo.cs" />

QuadHypComponent.cs

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ protected override void RegisterInputParams(GH_Component.GH_InputParamManager pM
8383
pManager.AddSurfaceParameter("QuadSurface", "QS", "QuadSurface", GH_ParamAccess.item);
8484
pManager.AddNumberParameter("UDim", "UD", "UDimension", GH_ParamAccess.item);
8585
pManager.AddNumberParameter("VDim", "VD", "VDimension", GH_ParamAccess.item);
86+
pManager.AddNumberParameter("Distance", "d", "OffsetDistance", GH_ParamAccess.item);
87+
pManager.AddNumberParameter("MinApertureRatio", "MinAR", "MinimumApertureRatio", GH_ParamAccess.item);
8688

8789
}
8890

@@ -91,10 +93,13 @@ protected override void RegisterInputParams(GH_Component.GH_InputParamManager pM
9193
/// </summary>
9294
protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
9395
{
94-
95-
pManager.AddTextParameter("info", "info", "info", GH_ParamAccess.item);
96-
pManager.AddGeometryParameter("TestOut", "TO", "TestOutput", GH_ParamAccess.list);
97-
96+
pManager.AddSurfaceParameter("Surface", "Srf", "SurfaceGenerated", GH_ParamAccess.item);
97+
pManager.AddCurveParameter("Curves2d", "Crv2d", "Result2dCurves", GH_ParamAccess.list);
98+
pManager.AddCurveParameter("Curves3d", "Crv3d", "Result3dCurves", GH_ParamAccess.list);
99+
pManager.AddMeshParameter("Meshes3d", "M3d", "Result3dMeshes", GH_ParamAccess.list);
100+
pManager.AddCurveParameter("TrimCurve3d", "TrCrv3d", "TrimEdges3dCurve", GH_ParamAccess.item);
101+
102+
98103

99104

100105
}
@@ -112,19 +117,23 @@ protected override void SolveInstance(IGH_DataAccess DA)
112117
Surface srf = null;
113118
double UDim = 99999999.99;
114119
double VDim = 99999999;
120+
double distance = 0.1;
121+
double minApertureRatio = 0.5;
115122

116123
// Use the DA object to retrieve the data inside the first input parameter.
117124
// If the retieval fails (for example if there is no data) we need to abort.
118125
if (!DA.GetData(0, ref srf)) { return; }
119126
if (!DA.GetData(1, ref UDim)) { return; }
120127
if (!DA.GetData(2, ref VDim)) { return; }
128+
if (!DA.GetData(3, ref distance)) { return; }
129+
if (!DA.GetData(4, ref minApertureRatio)) { return; }
130+
121131

122132
// If the retrieved data is Nothing, we need to abort.
123133
if (srf == null) { return; }
124134
if (UDim == 99999999.99) { return; }
125135
if (VDim == 99999999.99) { return; }
126136

127-
DA.SetData(0, "123a");
128137
Brep brep = srf.ToBrep();
129138
RhinoList<BrepEdge> edges = new RhinoList<BrepEdge>(brep.Edges);
130139
RhinoList<BrepEdge> sortedEdges = new RhinoList<BrepEdge>(brep.Edges);
@@ -189,18 +198,47 @@ protected override void SolveInstance(IGH_DataAccess DA)
189198
NurbsSurface newSrf = NurbsSurface.CreateFromCorners(topCurve.PointAtStart, topCurve.PointAtEnd, bottomCurve.PointAtStart, bottomCurve.PointAtEnd);
190199
//A = newSrf;
191200

201+
DA.SetData(0, newSrf);
202+
192203
SurfaceQuadSubdivision SQS = new SurfaceQuadSubdivision(newSrf, UCount, VCount);
193204
SQS.AddTrim(trimCurve);
194-
var A = SQS.GetAllTriangulatedPolygons();
195-
205+
206+
SQS.GetAllTriangulatedPolygons();
196207
SQS.CalculateTrims(true);
197208

198-
var B = SQS.resultCurves2d;
209+
var resultCurves2d = SQS.resultCurves2d;
210+
DA.SetDataList(1, resultCurves2d);
211+
var resultCurves3d = SQS.resultCurves3d;
212+
DA.SetDataList(2, resultCurves3d);
213+
214+
List<Mesh> meshes = new List<Mesh>();
215+
foreach (NurbsCurve curve in resultCurves2d)
216+
{
217+
List<Point3d> pts = new List<Point3d>();
218+
for (int i = 0; i < curve.SpanCount; i++)
219+
{
220+
pts.Add(curve.PointAt(curve.SpanDomain(i).T0));
221+
}
222+
pts.Add(pts[0]);
223+
224+
225+
OffsetHandler FHR = new OffsetHandler(new Polyline(pts), distance, minApertureRatio);
226+
List<Polyline> resultPolylines = new List<Polyline>();
227+
FHR.GetResultPolylines(out resultPolylines);
228+
Mesh mesh = new Mesh();
229+
foreach (Polyline polyline in resultPolylines)
230+
{
231+
FHR.GenerateMeshFromPolyLine(polyline, out mesh);
232+
SQS.UV2XYZ(ref mesh);
233+
meshes.Add(mesh);
234+
}
235+
}
199236

237+
DA.SetDataList(3, meshes);
200238

239+
DA.SetData(4, SQS.TrimCurve3d);
201240

202241

203-
DA.SetDataList(1, B);
204242

205243

206244

SurfaceQuadSubdivision.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,15 @@ public List<NurbsCurve> UV2XYZ(List<NurbsCurve> crvs2d)
367367
return crvs;
368368
}
369369

370+
public void UV2XYZ(ref Mesh mesh)
371+
{
372+
for (int i = 0; i < mesh.Vertices.Count; i++)
373+
{
374+
Point3d v = srf.PointAt(mesh.Vertices[i].X, mesh.Vertices[i].Y);
375+
mesh.Vertices[i] = new Point3f((float)v.X, (float)v.Y, (float)v.Z);
376+
}
377+
}
378+
370379
public NurbsSurface GetFacetedSurface3D(Interval UInterval, Interval VInterval)
371380
{
372381
Point3d A, B, C, D;

0 commit comments

Comments
 (0)