Skip to content

Commit

Permalink
General Completion - first state
Browse files Browse the repository at this point in the history
Known issues include curve offset side detection - could add as a manual input
  • Loading branch information
Chengxuan-Li committed Mar 1, 2023
1 parent c92f483 commit e157fe8
Show file tree
Hide file tree
Showing 4 changed files with 270 additions and 9 deletions.
213 changes: 213 additions & 0 deletions OffsetHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Rhino;
using Rhino.Geometry;
using Rhino.Collections;

namespace QuadHyp
{
public class OffsetHandler
{
public Polyline polyline;
public double distance;
public double maxAllowableDistance;
public double minApertureRatio;
public bool inputCurveIsValid = false;
public bool offsetSuccessful = false;

double area;

List<Line> lines = new List<Line>();
List<double> angles = new List<double>();
List<Point3d> points = new List<Point3d>();
List<Point3d> resultPoints = new List<Point3d>();
List<Line> resultLines = new List<Line>();
List<Polyline> resultPolylines = new List<Polyline>();
List<Mesh> resultMeshes = new List<Mesh>();


public OffsetHandler()
{
//
}

public OffsetHandler(Polyline _polyline, double _distance, double _minApertureRatio)
{
polyline = _polyline;
distance = _distance;
minApertureRatio = _minApertureRatio;

for (int i = 0; i < (polyline.Count - 1); i++)
{
points.Add(polyline[i]);
}

foreach (Line line in polyline.GetSegments())
{
lines.Add(line);
}

int count = polyline.Count;
if ((count <= 6) & (count >= 4))
{
inputCurveIsValid = true;
CalculateMaxAllowableDistance();
}

}

void CalculateMaxAllowableDistance()
{
AreaMassProperties AMP = AreaMassProperties.Compute(polyline.ToNurbsCurve());
area = AMP.Area;
maxAllowableDistance = area * (1 - minApertureRatio) / polyline.Length;
if (distance > maxAllowableDistance)
{
offsetSuccessful = false;
return;
}
else
{
offsetSuccessful = GenerateOffset();
}
}

bool GenerateOffset()
{
double crossProductResult = Vector3d.CrossProduct(new Vector3d(- lines[0].From + lines[0].To), new Vector3d(- lines[0].From + lines[1].To)).Z;
LineSide side = (crossProductResult > 0) ? LineSide.Right : LineSide.Left;
double rotateAngleCorrection = (side == LineSide.Left) ? - 1.0 : + 1.0;
//TODO still problem with deciding side

angles.Add(Math.PI - LineLineAngle(lines[lines.Count - 1], lines[0]));
for (int i = 0; i < (lines.Count - 1); i++)
{
angles.Add(Math.PI - LineLineAngle(lines[i], lines[i + 1]));
}

for (int i = 0; i < points.Count; i++)
{
int linesIndex = (i - 1 >= 0) ? (i - 1) : (points.Count - 1);
Vector3d direction = new Vector3d(lines[linesIndex].To - lines[linesIndex].From);
direction.Unitize();
direction.Rotate(rotateAngleCorrection * (Math.PI - 0.5 * angles[i]), Vector3d.ZAxis);
direction = direction * (distance / Math.Sin(angles[i] / 2));
resultPoints.Add(points[i] + direction);
}

for (int i = 0; i < (resultPoints.Count - 1); i++)
{
Line line = new Line(resultPoints[i + 1], resultPoints[i]);
resultLines.Add(line);
}
resultLines.Add(new Line(resultPoints[0], resultPoints[resultPoints.Count - 1]));


return true;
}

double LineLineAngle(Line line1, Line line2)
{
Vector3d vec1 = new Vector3d(line1.To - line1.From);
Vector3d vec2 = new Vector3d(line2.To - line2.From);
return Vector3d.VectorAngle(vec1, vec2);
}

public bool GetResultLines(out List<Line> result)
{
if (offsetSuccessful)
{
result = resultLines;
return offsetSuccessful;
} else
{
result = lines;
return offsetSuccessful;
}

}

public bool GetResultPolylines(out List<Polyline> result)
{
if (offsetSuccessful)
{
//Mesh mesh = new Mesh();
for (int i = 0; i < lines.Count; i++)
{
resultPolylines.Add(
new Polyline(
new List<Point3d>(){
lines[i].From,
lines[i].To,
resultLines[i].From,
resultLines[i].To,
lines[i].From
}));
}
result = resultPolylines;
return offsetSuccessful;
}
else
{
resultPolylines.Add(polyline);
result = resultPolylines;
return offsetSuccessful;
}
}



public bool GenerateMeshFromPolyLine(Polyline plyln, out Mesh mesh)
{
mesh = new Mesh();
if (plyln.Count == 4)
{
mesh.Vertices.Add(plyln[0]);
mesh.Vertices.Add(plyln[1]);
mesh.Vertices.Add(plyln[2]);
mesh.Faces.AddFace(0, 1, 2);
return true;
} else if (plyln.Count == 5)
{
mesh.Vertices.Add(plyln[0]);
mesh.Vertices.Add(plyln[1]);
mesh.Vertices.Add(plyln[2]);
mesh.Vertices.Add(plyln[3]);
mesh.Faces.AddFace(0, 1, 2, 3);
return true;
} else if (plyln.Count == 6)
{
mesh.Vertices.Add(plyln[0]);
mesh.Vertices.Add(plyln[1]);
mesh.Vertices.Add(plyln[2]);
mesh.Vertices.Add(plyln[3]);
mesh.Vertices.Add(plyln[4]);
mesh.Faces.AddFace(0, 1, 4);
mesh.Faces.AddFace(2, 3, 4);
return true;
} else if (plyln.Count == 7)
{
mesh.Vertices.Add(plyln[0]);
mesh.Vertices.Add(plyln[1]);
mesh.Vertices.Add(plyln[2]);
mesh.Vertices.Add(plyln[3]);
mesh.Vertices.Add(plyln[4]);
mesh.Vertices.Add(plyln[5]);
mesh.Faces.AddFace(0, 1, 4, 5);
mesh.Faces.AddFace(1, 2, 3, 4);
return true;
} else
{
return false;
}


}



}
}
1 change: 1 addition & 0 deletions QuadHyp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="LineLineAnalyticalIntersection2d.cs" />
<Compile Include="OffsetHandler.cs" />
<Compile Include="PolygonPolygonAnalyticalIntersection2d.cs" />
<Compile Include="QuadHypComponent.cs" />
<Compile Include="QuadHypInfo.cs" />
Expand Down
56 changes: 47 additions & 9 deletions QuadHypComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ protected override void RegisterInputParams(GH_Component.GH_InputParamManager pM
pManager.AddSurfaceParameter("QuadSurface", "QS", "QuadSurface", GH_ParamAccess.item);
pManager.AddNumberParameter("UDim", "UD", "UDimension", GH_ParamAccess.item);
pManager.AddNumberParameter("VDim", "VD", "VDimension", GH_ParamAccess.item);
pManager.AddNumberParameter("Distance", "d", "OffsetDistance", GH_ParamAccess.item);
pManager.AddNumberParameter("MinApertureRatio", "MinAR", "MinimumApertureRatio", GH_ParamAccess.item);

}

Expand All @@ -91,10 +93,13 @@ protected override void RegisterInputParams(GH_Component.GH_InputParamManager pM
/// </summary>
protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
{

pManager.AddTextParameter("info", "info", "info", GH_ParamAccess.item);
pManager.AddGeometryParameter("TestOut", "TO", "TestOutput", GH_ParamAccess.list);

pManager.AddSurfaceParameter("Surface", "Srf", "SurfaceGenerated", GH_ParamAccess.item);
pManager.AddCurveParameter("Curves2d", "Crv2d", "Result2dCurves", GH_ParamAccess.list);
pManager.AddCurveParameter("Curves3d", "Crv3d", "Result3dCurves", GH_ParamAccess.list);
pManager.AddMeshParameter("Meshes3d", "M3d", "Result3dMeshes", GH_ParamAccess.list);
pManager.AddCurveParameter("TrimCurve3d", "TrCrv3d", "TrimEdges3dCurve", GH_ParamAccess.item);




}
Expand All @@ -112,19 +117,23 @@ protected override void SolveInstance(IGH_DataAccess DA)
Surface srf = null;
double UDim = 99999999.99;
double VDim = 99999999;
double distance = 0.1;
double minApertureRatio = 0.5;

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


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

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

DA.SetData(0, newSrf);

SurfaceQuadSubdivision SQS = new SurfaceQuadSubdivision(newSrf, UCount, VCount);
SQS.AddTrim(trimCurve);
var A = SQS.GetAllTriangulatedPolygons();


SQS.GetAllTriangulatedPolygons();
SQS.CalculateTrims(true);

var B = SQS.resultCurves2d;
var resultCurves2d = SQS.resultCurves2d;
DA.SetDataList(1, resultCurves2d);
var resultCurves3d = SQS.resultCurves3d;
DA.SetDataList(2, resultCurves3d);

List<Mesh> meshes = new List<Mesh>();
foreach (NurbsCurve curve in resultCurves2d)
{
List<Point3d> pts = new List<Point3d>();
for (int i = 0; i < curve.SpanCount; i++)
{
pts.Add(curve.PointAt(curve.SpanDomain(i).T0));
}
pts.Add(pts[0]);


OffsetHandler FHR = new OffsetHandler(new Polyline(pts), distance, minApertureRatio);
List<Polyline> resultPolylines = new List<Polyline>();
FHR.GetResultPolylines(out resultPolylines);
Mesh mesh = new Mesh();
foreach (Polyline polyline in resultPolylines)
{
FHR.GenerateMeshFromPolyLine(polyline, out mesh);
SQS.UV2XYZ(ref mesh);
meshes.Add(mesh);
}
}

DA.SetDataList(3, meshes);

DA.SetData(4, SQS.TrimCurve3d);


DA.SetDataList(1, B);



Expand Down
9 changes: 9 additions & 0 deletions SurfaceQuadSubdivision.cs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,15 @@ public List<NurbsCurve> UV2XYZ(List<NurbsCurve> crvs2d)
return crvs;
}

public void UV2XYZ(ref Mesh mesh)
{
for (int i = 0; i < mesh.Vertices.Count; i++)
{
Point3d v = srf.PointAt(mesh.Vertices[i].X, mesh.Vertices[i].Y);
mesh.Vertices[i] = new Point3f((float)v.X, (float)v.Y, (float)v.Z);
}
}

public NurbsSurface GetFacetedSurface3D(Interval UInterval, Interval VInterval)
{
Point3d A, B, C, D;
Expand Down

0 comments on commit e157fe8

Please sign in to comment.